View Javadoc
1   package ejava.util.jndi;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.util.Properties;
6   
7   import javax.naming.Context;
8   import javax.naming.InitialContext;
9   import javax.naming.NameClassPair;
10  import javax.naming.NamingEnumeration;
11  import javax.naming.NamingException;
12  
13  import org.slf4j.Logger;
14  import org.slf4j.LoggerFactory;
15  
16  /**
17   * This class helps work with the JNDI tree.
18   */
19  public class JNDIUtil {
20  	private static final Logger logger = LoggerFactory.getLogger(JNDIUtil.class);
21  	public static final String PROPERTY_FILE="ejava-jndi.properties";
22  	private static final String[] PATHS = new String[]{
23  		"/" + PROPERTY_FILE, PROPERTY_FILE
24  	};
25  	
26  	/**
27  	 * This method will return a jndi.properties object that is based on the
28  	 * properties found in ejava-jndi.properties that start with the provided
29  	 * prefix. This method is useful when examples are using different JNDI
30  	 * mechanisms and want to keep them separate by forming the jndi.properties
31  	 * in memory.
32  	 * @param prefix
33  	 * @return Properties object that can be used during a new InitialContext(env)
34  	 * @throws IOException
35  	 */
36      public static Properties getJNDIProperties(String prefix) throws IOException {
37      	InputStream is = null;
38      	for (int i=0; is==null && i<PATHS.length; i++) {
39      		logger.debug("trying: " + PATHS[i]);
40      		is = JNDIUtil.class.getResourceAsStream(PATHS[i]);
41      	}
42      	for (int i=0; is==null && i<PATHS.length; i++) {
43      		logger.debug("trying loader for thread: " + PATHS[i]);
44      		is = Thread.currentThread().getContextClassLoader().getResourceAsStream(PATHS[i]);
45      	}
46      	
47      	Properties env = new Properties();
48      	if (is!=null) {
49          	Properties props = new Properties();
50          	props.load(is);
51          	is.close();
52          	
53          	for (String key : props.stringPropertyNames()) {
54          		String value = props.getProperty(key);
55          		if (key.startsWith(prefix) && value != null && !value.isEmpty()) {
56          			String name=key.substring(prefix.length(),key.length());
57          			env.put(name, value);
58          		}
59          	}
60      	} else {
61      		logger.warn("unable to locate ejava-jndi.properties from classpath");
62      	}
63      	return env;
64      }
65  	
66      /**
67       * Performs a JNDI lookup and will wait supplied number of seconds before 
68       * giving up.
69       * @param ctx
70       * @param type
71       * @param name
72       * @param waitSecs
73       * @return Object resolved from the lookup
74       * @throws NamingException 
75       */
76      @SuppressWarnings("unchecked")
77  	public static <T> T lookup(Context ctx, Class<T> type, String name, int waitSecs) 
78  			throws NamingException {
79      	logger.debug(String.format("looking up %s, wait=%d", name, waitSecs));
80      	
81      	T object=null;
82      	//wait increments should be at least 1sec
83      	long interval=Math.max(waitSecs*1000/10, 1000);
84      	for (int elapsed=0; elapsed<(waitSecs*1000); elapsed += interval) {
85      		if (elapsed + interval < waitSecs*1000) {
86  	    		try {
87  					object = (T) ctx.lookup(name);
88  				} catch (Throwable ex) {
89  					logger.debug(String.format("error in jndi.lookup(%s)=%s", name, ex));
90  					try { Thread.sleep(interval); } catch (Exception ex2) {}
91  				}
92      		} else {
93  				object = (T) ctx.lookup(name);
94      		}
95      	}
96      	logger.debug("object=" + object);
97      	return object;
98      }
99  		
100 	/**
101      * Produces a debug string listing the JNDI contents of the current, default 
102      * Context.
103      * @return String describing contents of context
104 	 * @throws NamingException
105 	 */
106     public String dump() throws NamingException {
107         return dump(new InitialContext(),"");
108     }
109 
110     /**
111      * Produces a debug string listing the JNDI contents of the specified 
112      * Context.
113      * @param context
114      * @param name
115      * @return String describing contents of context
116      */
117     public String dump(Context context, String name) {
118         StringBuilder text = new StringBuilder();
119         if (name==null) { name = ""; }
120         try {
121             text.append("listing ").append(name);
122             doDump(0, text, context, name);
123         }
124         catch (NamingException ex) {}
125         return text.toString();
126     }
127 
128 	private void doDump(int level, StringBuilder text, Context context, String name) 
129         throws NamingException {
130         for (NamingEnumeration<NameClassPair> ne = context.list(name); ne.hasMore();) {
131             NameClassPair ncp = (NameClassPair) ne.next();
132             String objectName = ncp.getName();
133             String className = ncp.getClassName();
134             if (isContext(className)) {
135             	text.append(getPad(level))
136             	    .append("+")
137             	    .append(objectName)
138             	    .append(":")
139             	    .append(className)
140             	    .append('\n');
141                 doDump(level + 1, text, context, name + "/" + objectName);
142             } else {
143             	text.append(getPad(level))
144 	        	    .append("-")
145 	        	    .append(objectName)
146 	        	    .append(":")
147 	        	    .append(className)
148 	        	    .append('\n');
149             }
150         }
151     }
152     
153 	protected boolean isContext(String className) {
154         try {
155 			Class<?> objectClass = Thread.currentThread().getContextClassLoader()
156                     .loadClass(className);
157             return Context.class.isAssignableFrom(objectClass);
158         }
159         catch (ClassNotFoundException ex) {
160             //object is probably not a context, report as non-context
161             return false;
162         }
163     }
164 
165     protected String getPad(int level) {
166         StringBuilder pad = new StringBuilder();
167         for (int i = 0; i < level; i++) {
168             pad.append(" ");
169         }
170         return pad.toString();
171     }
172 }