001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.naming.core;
018:
019: import java.util.Enumeration;
020: import java.util.Hashtable;
021:
022: import javax.naming.CompositeName;
023: import javax.naming.InvalidNameException;
024: import javax.naming.Name;
025: import javax.naming.NameParser;
026: import javax.naming.NamingException;
027: import javax.naming.OperationNotSupportedException;
028: import javax.naming.directory.Attributes;
029: import javax.naming.directory.DirContext;
030:
031: import org.apache.tomcat.util.IntrospectionUtils;
032:
033: // Based on a merge of various catalina naming contexts
034: // Name is used - it provide better oportunities for reuse and optimizations
035:
036: /**
037: * This is the base class for our naming operations, for easy reading.
038: *
039: * <p>Creating a new context:
040: * <ul>
041: * <li>Create a new class, extending BaseContext or BaseDirContext ( second
042: * if you want to support attributes ).
043: * <li>Add setters for configuration. The setters will be called autmatically,
044: * like in ant, from the initial env settings.
045: * <li>Override methods that are defined in BaseNaming. Default behavior
046: * is provided for all.
047: * <li>If performance is a concern or have special behavior - override Context and
048: * DirContext methods. That shouldn't be needed in most cases.
049: * </ul>
050: *
051: * This class is designed to minimize the ammount of code that is required to
052: * create a new context. The usual DirContext interface has way too many methods,
053: * so implementation requires a lot of typing.
054: *
055: * Our contexts are mostly wrappers for files or in memory structures. That means
056: * some operations are cheaper, and we're far from the features that would be
057: * exposed for an LDAP or real Directory server.
058: *
059: * @author Remy Maucherat
060: * @author Costin Manolache
061: */
062: public class BaseNaming {
063:
064: /**
065: * Builds a base directory context.
066: */
067: public BaseNaming() {
068: this .env = new Hashtable();
069: }
070:
071: /**
072: * Builds a base directory context using the given environment.
073: */
074: public BaseNaming(Hashtable env) {
075: this .env = new Hashtable();
076: if (env != null) {
077: Enumeration envEntries = env.keys();
078: while (envEntries.hasMoreElements()) {
079: String entryName = (String) envEntries.nextElement();
080: Object entryValue = env.get(entryName);
081: this .env.put(entryName, entryValue);
082: try {
083: // XXX We need a mechanism to select properties for
084: // this task. Maybe all contexts should use as property prefix the
085: // class name ? Or base class name ?
086: IntrospectionUtils.setAttribute(this , entryName,
087: entryValue);
088: } catch (Exception ex) {
089: System.out.println("Unsuported property "
090: + entryName + " " + ex.getMessage());
091: }
092: }
093: }
094: }
095:
096: // ----------------------------------------------------- Instance Variables
097:
098: /**
099: * Environment. All context config info.
100: */
101: protected Hashtable env;
102:
103: /**
104: * Default name parser for this context.
105: * XXX This should be combined with the Tomcat mapper, and
106: * optimized for MessageBytes.
107: */
108: protected final NameParser nameParser = new NameParserImpl();
109:
110: /** Prefix used for URL-based namming lookup. It must be removed
111: * from all names.
112: * Deprecated ? Do we need it ?
113: */
114: protected String urlPrefix = "";
115:
116: // ------------------------------------------------------------- Properties
117: // Common properties, apply to all jtc naming contexts.
118:
119: // XXX Introspection should be used to turn the Hashtable attributes
120: // into setters.
121: public void setURLPrefix(String s) {
122: urlPrefix = s;
123: }
124:
125: private boolean cached;
126: private int cacheTTL;
127: private int cacheObjectMaxSize;
128:
129: public boolean isCached() {
130: return cached;
131: }
132:
133: public void setCached(boolean cached) {
134: this .cached = cached;
135: }
136:
137: public int getCacheTTL() {
138: return cacheTTL;
139: }
140:
141: public void setCacheTTL(int cacheTTL) {
142: this .cacheTTL = cacheTTL;
143: }
144:
145: public int getCacheObjectMaxSize() {
146: return cacheObjectMaxSize;
147: }
148:
149: public void setCacheObjectMaxSize(int cacheObjectMaxSize) {
150: this .cacheObjectMaxSize = cacheObjectMaxSize;
151: }
152:
153: // -------------------- Not so Abstract methods --------------------
154: // This is what a subclass should implement.
155:
156: // XXX Base resolveLinks() method ?? And then use lookup without resolveLinks flag
157:
158: /** The lookup method. This is the main method you should implement.
159: *
160: * @param name
161: * @param resolveLinks If false, this is a lookupLink call.
162: */
163: public Object lookup(Name name, boolean resolveLinks)
164: throws NamingException {
165: throw new OperationNotSupportedException();
166: }
167:
168: /** The setter method. Implement it if the context is read/write.
169: *
170: * @param name
171: * @param obj The object to be bound.
172: * @param attrs Attributes - if this is a dir context, null otherwise
173: * @param rebind What to do if the name is already bound.
174: * XXX can be further simplified - do a lookup and implement it.
175: */
176: public void bind(Name name, Object obj, Attributes attrs,
177: boolean rebind) throws NamingException {
178: throw new OperationNotSupportedException();
179: }
180:
181: /** Remove a binding. XXX do we need the isContext case ?
182: */
183: public void unbind(Name name, boolean isContext)
184: throws NamingException {
185: throw new OperationNotSupportedException();
186: }
187:
188: /* XXX There are 2 ways to list the childs: array ( size/elementAt ) or
189: iterator/Enumeration. Since the JNDI interface uses iteration -
190: that's what we should use.
191: */
192:
193: /** Return the child elements, if any.
194: *
195: * This is a String or Name or Binding or NameClassPari enumeration -
196: * the Context implementation will wrap it as a NamingEnumeration and
197: * construct the right information.
198: *
199: * XXX name is all we need - all other info can be extracted - with some
200: * penalty. It's easy to do some instanceof tricks to avoid it, if possible,
201: * but the goal is to make it easy to write contexts, and name should be
202: * enough.
203: */
204: public Enumeration getChildren() throws NamingException {
205: return null;
206: }
207:
208: public DirContext createSubcontext(Name name, Attributes attrs)
209: throws NamingException {
210: // XXX We can implement a decent default using bind and the current class.
211: throw new OperationNotSupportedException();
212: }
213:
214: /** Implement for directories
215: *
216: */
217: public Object getAttribute(Name name, String attName)
218: throws NamingException {
219: throw new OperationNotSupportedException();
220: }
221:
222: public void setAttribute(Name name, String attName, Object value)
223: throws NamingException {
224: throw new OperationNotSupportedException();
225: }
226:
227: public String[] getAttributeNames(Name name) throws NamingException {
228: throw new OperationNotSupportedException();
229: }
230:
231: // -------------------- Utils --------------------
232: // XXX Implement this
233:
234: /**
235: * Returns true if writing is allowed on this context.
236: */
237: protected boolean isWritable(Name name) {
238: return true;
239: //return ContextAccessController.isWritable(name);
240: }
241:
242: /**
243: * Throws a naming exception is Context is not writable.
244: */
245: protected void checkWritable(Name n) throws NamingException {
246: if (!isWritable(n))
247: throw new NamingException("read only");
248: }
249:
250: protected Name string2Name(String s) throws InvalidNameException {
251: // XXX uniq
252: // try {
253: return new CompositeName(s);
254: // } catch( InvalidNameException ex ) {
255: // ex.printStackTrace();
256: // return null;
257: // }
258: }
259:
260: // -------------------- Lifecycle methods ? --------------------
261:
262: /**
263: * Allocate resources for this directory context.
264: */
265: public void allocate() {
266: ; // No action taken by the default implementation
267: }
268:
269: /**
270: * Release any resources allocated for this directory context.
271: */
272: public void release() {
273: ; // No action taken by the default implementation
274: }
275:
276: public void recycle() {
277: // nothing yet.
278: }
279:
280: //-------------------- Helpers --------------------
281:
282: /** Just a hack so that all DirContexts can be used as tasks.
283: * They'll do nothing - the setters will be called ( just like
284: * new Context(Hashtable) - since we use introspection ) and the
285: * context can be registred as a reference in the Project ns.
286: *
287: * Then other tasks could manipulate it by name.
288: *
289: * In a future version of ant we should have the 'references'
290: * pluggable and a possible impl should be JNDI.
291: *
292: * Alternative: there is a way to use tasks without this method,
293: * but for now it's simpler.
294: */
295: public void execute() {
296: }
297: }
|