0001: package com.flexive.war.webdav.catalina;
0002:
0003: import com.flexive.shared.FxSharedUtils;
0004:
0005: import javax.naming.*;
0006: import javax.naming.directory.Attributes;
0007: import javax.naming.directory.DirContext;
0008: import javax.naming.directory.ModificationItem;
0009: import javax.naming.directory.SearchControls;
0010: import java.io.ByteArrayInputStream;
0011: import java.io.IOException;
0012: import java.io.InputStream;
0013: import java.util.Hashtable;
0014:
0015: /**
0016: * Catalina sources cloned for packaging issues to the flexive source tree.
0017: * Refactored to JDK 1.5 compatibility.
0018: * Licensed under the Apache License, Version 2.0
0019: * <p/>
0020: * Proxy Directory Context implementation.
0021: *
0022: * @author Remy Maucherat
0023: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
0024: */
0025:
0026: public class ProxyDirContext implements DirContext {
0027:
0028: // -------------------------------------------------------------- Constants
0029:
0030: public static final String CONTEXT = "context";
0031: public static final String HOST = "host";
0032:
0033: // ----------------------------------------------------------- Constructors
0034:
0035: /**
0036: * Builds a proxy directory context using the given environment.
0037: */
0038: public ProxyDirContext(Hashtable env, DirContext dirContext) {
0039: this .env = env;
0040: this .dirContext = dirContext;
0041: if (dirContext instanceof BaseDirContext) {
0042: // Initialize parameters based on the associated dir context, like
0043: // the caching policy.
0044: BaseDirContext baseDirContext = (BaseDirContext) dirContext;
0045: if (baseDirContext.isCached()) {
0046: try {
0047: cache = (ResourceCache) Class.forName(
0048: cacheClassName).newInstance();
0049: } catch (Exception e) {
0050: //FIXME
0051: e.printStackTrace();
0052: }
0053: cache.setCacheMaxSize(baseDirContext.getCacheMaxSize());
0054: cacheTTL = baseDirContext.getCacheTTL();
0055: cacheObjectMaxSize = baseDirContext.getCacheMaxSize() / 20;
0056: }
0057: }
0058: hostName = (String) env.get(HOST);
0059: contextName = (String) env.get(CONTEXT);
0060: }
0061:
0062: /**
0063: * Builds a clone of this proxy dir context, wrapping the given directory
0064: * context, and sharing the same cache.
0065: */
0066: // TODO: Refactor using the proxy field
0067: /*
0068: protected ProxyDirContext(ProxyDirContext proxyDirContext,
0069: DirContext dirContext, String vPath) {
0070: this.env = proxyDirContext.env;
0071: this.dirContext = dirContext;
0072: this.vPath = vPath;
0073: this.cache = proxyDirContext.cache;
0074: this.cacheMaxSize = proxyDirContext.cacheMaxSize;
0075: this.cacheSize = proxyDirContext.cacheSize;
0076: this.cacheTTL = proxyDirContext.cacheTTL;
0077: this.cacheObjectMaxSize = proxyDirContext.cacheObjectMaxSize;
0078: this.notFoundCache = proxyDirContext.notFoundCache;
0079: this.hostName = proxyDirContext.hostName;
0080: this.contextName = proxyDirContext.contextName;
0081: }
0082: */
0083:
0084: // ----------------------------------------------------- Instance Variables
0085:
0086: /**
0087: * Proxy DirContext (either this or the real proxy).
0088: */
0089: protected ProxyDirContext proxy = this ;
0090:
0091: /**
0092: * Environment.
0093: */
0094: protected Hashtable env;
0095:
0096: /**
0097: * The string manager for this package.
0098: */
0099: // protected StringManager sm = StringManager.getManager(Constants.Package);
0100:
0101: /**
0102: * Associated DirContext.
0103: */
0104: protected DirContext dirContext;
0105:
0106: /**
0107: * Virtual path.
0108: */
0109: protected String vPath = null;
0110:
0111: /**
0112: * Host name.
0113: */
0114: protected String hostName;
0115:
0116: /**
0117: * Context name.
0118: */
0119: protected String contextName;
0120:
0121: /**
0122: * Cache class.
0123: */
0124: protected String cacheClassName = "org.apache.naming.resources.ResourceCache";
0125:
0126: /**
0127: * Cache.
0128: */
0129: protected ResourceCache cache = null;
0130:
0131: /**
0132: * Cache TTL.
0133: */
0134: protected int cacheTTL = 5000; // 5s
0135:
0136: /**
0137: * Max size of resources which will have their content cached.
0138: */
0139: protected int cacheObjectMaxSize = 512; // 512 KB
0140:
0141: /**
0142: * Immutable name not found exception.
0143: */
0144: protected NameNotFoundException notFoundException = new ImmutableNameNotFoundException();
0145:
0146: /**
0147: * Non cacheable resources.
0148: */
0149: protected String[] nonCacheable = { "/WEB-INF/lib/",
0150: "/WEB-INF/classes/" };
0151:
0152: // --------------------------------------------------------- Public Methods
0153:
0154: /**
0155: * Get the cache used for this context.
0156: */
0157: public ResourceCache getCache() {
0158: return cache;
0159: }
0160:
0161: /**
0162: * Return the actual directory context we are wrapping.
0163: */
0164: public DirContext getDirContext() {
0165: return this .dirContext;
0166: }
0167:
0168: /**
0169: * Return the document root for this component.
0170: */
0171: public String getDocBase() {
0172: if (dirContext instanceof BaseDirContext)
0173: return ((BaseDirContext) dirContext).getDocBase();
0174: else
0175: return "";
0176: }
0177:
0178: /**
0179: * Return the host name.
0180: */
0181: public String getHostName() {
0182: return this .hostName;
0183: }
0184:
0185: /**
0186: * Return the context name.
0187: */
0188: public String getContextName() {
0189: return this .contextName;
0190: }
0191:
0192: // -------------------------------------------------------- Context Methods
0193:
0194: /**
0195: * Retrieves the named object. If name is empty, returns a new instance
0196: * of this context (which represents the same naming context as this
0197: * context, but its environment may be modified independently and it may
0198: * be accessed concurrently).
0199: *
0200: * @param name the name of the object to look up
0201: * @return the object bound to name
0202: * @throws NamingException if a naming exception is encountered
0203: */
0204: public Object lookup(Name name) throws NamingException {
0205: CacheEntry entry = cacheLookup(name.toString());
0206: if (entry != null) {
0207: if (!entry.exists) {
0208: throw notFoundException;
0209: }
0210: if (entry.resource != null) {
0211: // Check content caching.
0212: return entry.resource;
0213: } else {
0214: return entry.context;
0215: }
0216: }
0217: Object object = dirContext.lookup(parseName(name));
0218: if (object instanceof InputStream)
0219: return new Resource((InputStream) object);
0220: else
0221: return object;
0222: }
0223:
0224: /**
0225: * Retrieves the named object.
0226: *
0227: * @param name the name of the object to look up
0228: * @return the object bound to name
0229: * @throws NamingException if a naming exception is encountered
0230: */
0231: public Object lookup(String name) throws NamingException {
0232: CacheEntry entry = cacheLookup(name);
0233: if (entry != null) {
0234: if (!entry.exists) {
0235: throw notFoundException;
0236: }
0237: if (entry.resource != null) {
0238: return entry.resource;
0239: } else {
0240: return entry.context;
0241: }
0242: }
0243: Object object = dirContext.lookup(parseName(name));
0244: if (object instanceof InputStream) {
0245: return new Resource((InputStream) object);
0246: } else if (object instanceof DirContext) {
0247: return object;
0248: } else if (object instanceof Resource) {
0249: return object;
0250: } else {
0251: return new Resource(new ByteArrayInputStream(FxSharedUtils
0252: .getBytes(object.toString())));
0253: }
0254: }
0255:
0256: /**
0257: * Binds a name to an object. All intermediate contexts and the target
0258: * context (that named by all but terminal atomic component of the name)
0259: * must already exist.
0260: *
0261: * @param name the name to bind; may not be empty
0262: * @param obj the object to bind; possibly null
0263: * @throws NamingException if a naming exception is encountered
0264: */
0265: public void bind(Name name, Object obj) throws NamingException {
0266: dirContext.bind(parseName(name), obj);
0267: cacheUnload(name.toString());
0268: }
0269:
0270: /**
0271: * Binds a name to an object.
0272: *
0273: * @param name the name to bind; may not be empty
0274: * @param obj the object to bind; possibly null
0275: * @throws NamingException if a naming exception is encountered
0276: */
0277: public void bind(String name, Object obj) throws NamingException {
0278: dirContext.bind(parseName(name), obj);
0279: cacheUnload(name);
0280: }
0281:
0282: /**
0283: * Binds a name to an object, overwriting any existing binding. All
0284: * intermediate contexts and the target context (that named by all but
0285: * terminal atomic component of the name) must already exist.
0286: * <p/>
0287: * If the object is a DirContext, any existing attributes associated with
0288: * the name are replaced with those of the object. Otherwise, any
0289: * existing attributes associated with the name remain unchanged.
0290: *
0291: * @param name the name to bind; may not be empty
0292: * @param obj the object to bind; possibly null
0293: * @throws NamingException if a naming exception is encountered
0294: */
0295: public void rebind(Name name, Object obj) throws NamingException {
0296: dirContext.rebind(parseName(name), obj);
0297: cacheUnload(name.toString());
0298: }
0299:
0300: /**
0301: * Binds a name to an object, overwriting any existing binding.
0302: *
0303: * @param name the name to bind; may not be empty
0304: * @param obj the object to bind; possibly null
0305: * @throws NamingException if a naming exception is encountered
0306: */
0307: public void rebind(String name, Object obj) throws NamingException {
0308: dirContext.rebind(parseName(name), obj);
0309: cacheUnload(name);
0310: }
0311:
0312: /**
0313: * Unbinds the named object. Removes the terminal atomic name in name
0314: * from the target context--that named by all but the terminal atomic
0315: * part of name.
0316: * <p/>
0317: * This method is idempotent. It succeeds even if the terminal atomic
0318: * name is not bound in the target context, but throws
0319: * NameNotFoundException if any of the intermediate contexts do not exist.
0320: *
0321: * @param name the name to bind; may not be empty
0322: * @throws NameNotFoundException if an intermediate context does not
0323: * exist
0324: * @throws NamingException if a naming exception is encountered
0325: */
0326: public void unbind(Name name) throws NamingException {
0327: dirContext.unbind(parseName(name));
0328: cacheUnload(name.toString());
0329: }
0330:
0331: /**
0332: * Unbinds the named object.
0333: *
0334: * @param name the name to bind; may not be empty
0335: * @throws NameNotFoundException if an intermediate context does not
0336: * exist
0337: * @throws NamingException if a naming exception is encountered
0338: */
0339: public void unbind(String name) throws NamingException {
0340: dirContext.unbind(parseName(name));
0341: cacheUnload(name);
0342: }
0343:
0344: /**
0345: * Binds a new name to the object bound to an old name, and unbinds the
0346: * old name. Both names are relative to this context. Any attributes
0347: * associated with the old name become associated with the new name.
0348: * Intermediate contexts of the old name are not changed.
0349: *
0350: * @param oldName the name of the existing binding; may not be empty
0351: * @param newName the name of the new binding; may not be empty
0352: * @throws NamingException if a naming exception is encountered
0353: */
0354: public void rename(Name oldName, Name newName)
0355: throws NamingException {
0356: dirContext.rename(parseName(oldName), parseName(newName));
0357: cacheUnload(oldName.toString());
0358: }
0359:
0360: /**
0361: * Binds a new name to the object bound to an old name, and unbinds the
0362: * old name.
0363: *
0364: * @param oldName the name of the existing binding; may not be empty
0365: * @param newName the name of the new binding; may not be empty
0366: * @throws NamingException if a naming exception is encountered
0367: */
0368: public void rename(String oldName, String newName)
0369: throws NamingException {
0370: dirContext.rename(parseName(oldName), parseName(newName));
0371: cacheUnload(oldName);
0372: }
0373:
0374: /**
0375: * Enumerates the names bound in the named context, along with the class
0376: * names of objects bound to them. The contents of any subcontexts are
0377: * not included.
0378: * <p/>
0379: * If a binding is added to or removed from this context, its effect on
0380: * an enumeration previously returned is undefined.
0381: *
0382: * @param name the name of the context to list
0383: * @return an enumeration of the names and class names of the bindings in
0384: * this context. Each element of the enumeration is of type NameClassPair.
0385: * @throws NamingException if a naming exception is encountered
0386: */
0387: public NamingEnumeration list(Name name) throws NamingException {
0388: return dirContext.list(parseName(name));
0389: }
0390:
0391: /**
0392: * Enumerates the names bound in the named context, along with the class
0393: * names of objects bound to them.
0394: *
0395: * @param name the name of the context to list
0396: * @return an enumeration of the names and class names of the bindings in
0397: * this context. Each element of the enumeration is of type NameClassPair.
0398: * @throws NamingException if a naming exception is encountered
0399: */
0400: public NamingEnumeration list(String name) throws NamingException {
0401: return dirContext.list(parseName(name));
0402: }
0403:
0404: /**
0405: * Enumerates the names bound in the named context, along with the
0406: * objects bound to them. The contents of any subcontexts are not
0407: * included.
0408: * <p/>
0409: * If a binding is added to or removed from this context, its effect on
0410: * an enumeration previously returned is undefined.
0411: *
0412: * @param name the name of the context to list
0413: * @return an enumeration of the bindings in this context.
0414: * Each element of the enumeration is of type Binding.
0415: * @throws NamingException if a naming exception is encountered
0416: */
0417: public NamingEnumeration listBindings(Name name)
0418: throws NamingException {
0419: return dirContext.listBindings(parseName(name));
0420: }
0421:
0422: /**
0423: * Enumerates the names bound in the named context, along with the
0424: * objects bound to them.
0425: *
0426: * @param name the name of the context to list
0427: * @return an enumeration of the bindings in this context.
0428: * Each element of the enumeration is of type Binding.
0429: * @throws NamingException if a naming exception is encountered
0430: */
0431: public NamingEnumeration listBindings(String name)
0432: throws NamingException {
0433: return dirContext.listBindings(parseName(name));
0434: }
0435:
0436: /**
0437: * Destroys the named context and removes it from the namespace. Any
0438: * attributes associated with the name are also removed. Intermediate
0439: * contexts are not destroyed.
0440: * <p/>
0441: * This method is idempotent. It succeeds even if the terminal atomic
0442: * name is not bound in the target context, but throws
0443: * NameNotFoundException if any of the intermediate contexts do not exist.
0444: * <p/>
0445: * In a federated naming system, a context from one naming system may be
0446: * bound to a name in another. One can subsequently look up and perform
0447: * operations on the foreign context using a composite name. However, an
0448: * attempt destroy the context using this composite name will fail with
0449: * NotContextException, because the foreign context is not a "subcontext"
0450: * of the context in which it is bound. Instead, use unbind() to remove
0451: * the binding of the foreign context. Destroying the foreign context
0452: * requires that the destroySubcontext() be performed on a context from
0453: * the foreign context's "native" naming system.
0454: *
0455: * @param name the name of the context to be destroyed; may not be empty
0456: * @throws NameNotFoundException if an intermediate context does not
0457: * exist
0458: */
0459: public void destroySubcontext(Name name) throws NamingException {
0460: dirContext.destroySubcontext(parseName(name));
0461: cacheUnload(name.toString());
0462: }
0463:
0464: /**
0465: * Destroys the named context and removes it from the namespace.
0466: *
0467: * @param name the name of the context to be destroyed; may not be empty
0468: * @throws NameNotFoundException if an intermediate context does not
0469: * exist
0470: */
0471: public void destroySubcontext(String name) throws NamingException {
0472: dirContext.destroySubcontext(parseName(name));
0473: cacheUnload(name);
0474: }
0475:
0476: /**
0477: * Creates and binds a new context. Creates a new context with the given
0478: * name and binds it in the target context (that named by all but
0479: * terminal atomic component of the name). All intermediate contexts and
0480: * the target context must already exist.
0481: *
0482: * @param name the name of the context to create; may not be empty
0483: * @return the newly created context
0484: * @throws NamingException if a naming exception is encountered
0485: */
0486: public Context createSubcontext(Name name) throws NamingException {
0487: Context context = dirContext.createSubcontext(parseName(name));
0488: cacheUnload(name.toString());
0489: return context;
0490: }
0491:
0492: /**
0493: * Creates and binds a new context.
0494: *
0495: * @param name the name of the context to create; may not be empty
0496: * @return the newly created context
0497: * @throws NamingException if a naming exception is encountered
0498: */
0499: public Context createSubcontext(String name) throws NamingException {
0500: Context context = dirContext.createSubcontext(parseName(name));
0501: cacheUnload(name);
0502: return context;
0503: }
0504:
0505: /**
0506: * Retrieves the named object, following links except for the terminal
0507: * atomic component of the name. If the object bound to name is not a
0508: * link, returns the object itself.
0509: *
0510: * @param name the name of the object to look up
0511: * @return the object bound to name, not following the terminal link
0512: * (if any).
0513: * @throws NamingException if a naming exception is encountered
0514: */
0515: public Object lookupLink(Name name) throws NamingException {
0516: return dirContext.lookupLink(parseName(name));
0517: }
0518:
0519: /**
0520: * Retrieves the named object, following links except for the terminal
0521: * atomic component of the name.
0522: *
0523: * @param name the name of the object to look up
0524: * @return the object bound to name, not following the terminal link
0525: * (if any).
0526: * @throws NamingException if a naming exception is encountered
0527: */
0528: public Object lookupLink(String name) throws NamingException {
0529: return dirContext.lookupLink(parseName(name));
0530: }
0531:
0532: /**
0533: * Retrieves the parser associated with the named context. In a
0534: * federation of namespaces, different naming systems will parse names
0535: * differently. This method allows an application to get a parser for
0536: * parsing names into their atomic components using the naming convention
0537: * of a particular naming system. Within any single naming system,
0538: * NameParser objects returned by this method must be equal (using the
0539: * equals() test).
0540: *
0541: * @param name the name of the context from which to get the parser
0542: * @return a name parser that can parse compound names into their atomic
0543: * components
0544: * @throws NamingException if a naming exception is encountered
0545: */
0546: public NameParser getNameParser(Name name) throws NamingException {
0547: return dirContext.getNameParser(parseName(name));
0548: }
0549:
0550: /**
0551: * Retrieves the parser associated with the named context.
0552: *
0553: * @param name the name of the context from which to get the parser
0554: * @return a name parser that can parse compound names into their atomic
0555: * components
0556: * @throws NamingException if a naming exception is encountered
0557: */
0558: public NameParser getNameParser(String name) throws NamingException {
0559: return dirContext.getNameParser(parseName(name));
0560: }
0561:
0562: /**
0563: * Composes the name of this context with a name relative to this context.
0564: * <p/>
0565: * Given a name (name) relative to this context, and the name (prefix)
0566: * of this context relative to one of its ancestors, this method returns
0567: * the composition of the two names using the syntax appropriate for the
0568: * naming system(s) involved. That is, if name names an object relative
0569: * to this context, the result is the name of the same object, but
0570: * relative to the ancestor context. None of the names may be null.
0571: *
0572: * @param name a name relative to this context
0573: * @param prefix the name of this context relative to one of its ancestors
0574: * @return the composition of prefix and name
0575: * @throws NamingException if a naming exception is encountered
0576: */
0577: public Name composeName(Name name, Name prefix)
0578: throws NamingException {
0579: prefix = (Name) prefix.clone();
0580: return prefix.addAll(name);
0581: }
0582:
0583: /**
0584: * Composes the name of this context with a name relative to this context.
0585: *
0586: * @param name a name relative to this context
0587: * @param prefix the name of this context relative to one of its ancestors
0588: * @return the composition of prefix and name
0589: * @throws NamingException if a naming exception is encountered
0590: */
0591: public String composeName(String name, String prefix)
0592: throws NamingException {
0593: return prefix + "/" + name;
0594: }
0595:
0596: /**
0597: * Adds a new environment property to the environment of this context. If
0598: * the property already exists, its value is overwritten.
0599: *
0600: * @param propName the name of the environment property to add; may not
0601: * be null
0602: * @param propVal the value of the property to add; may not be null
0603: * @throws NamingException if a naming exception is encountered
0604: */
0605: public Object addToEnvironment(String propName, Object propVal)
0606: throws NamingException {
0607: return dirContext.addToEnvironment(propName, propVal);
0608: }
0609:
0610: /**
0611: * Removes an environment property from the environment of this context.
0612: *
0613: * @param propName the name of the environment property to remove;
0614: * may not be null
0615: * @throws NamingException if a naming exception is encountered
0616: */
0617: public Object removeFromEnvironment(String propName)
0618: throws NamingException {
0619: return dirContext.removeFromEnvironment(propName);
0620: }
0621:
0622: /**
0623: * Retrieves the environment in effect for this context. See class
0624: * description for more details on environment properties.
0625: * The caller should not make any changes to the object returned: their
0626: * effect on the context is undefined. The environment of this context
0627: * may be changed using addToEnvironment() and removeFromEnvironment().
0628: *
0629: * @return the environment of this context; never null
0630: * @throws NamingException if a naming exception is encountered
0631: */
0632: public Hashtable getEnvironment() throws NamingException {
0633: return dirContext.getEnvironment();
0634: }
0635:
0636: /**
0637: * Closes this context. This method releases this context's resources
0638: * immediately, instead of waiting for them to be released automatically
0639: * by the garbage collector.
0640: * This method is idempotent: invoking it on a context that has already
0641: * been closed has no effect. Invoking any other method on a closed
0642: * context is not allowed, and results in undefined behaviour.
0643: *
0644: * @throws NamingException if a naming exception is encountered
0645: */
0646: public void close() throws NamingException {
0647: dirContext.close();
0648: }
0649:
0650: /**
0651: * Retrieves the full name of this context within its own namespace.
0652: * <p/>
0653: * Many naming services have a notion of a "full name" for objects in
0654: * their respective namespaces. For example, an LDAP entry has a
0655: * distinguished name, and a DNS record has a fully qualified name. This
0656: * method allows the client application to retrieve this name. The string
0657: * returned by this method is not a JNDI composite name and should not be
0658: * passed directly to context methods. In naming systems for which the
0659: * notion of full name does not make sense,
0660: * OperationNotSupportedException is thrown.
0661: *
0662: * @return this context's name in its own namespace; never null
0663: * @throws NamingException if a naming exception is encountered
0664: */
0665: public String getNameInNamespace() throws NamingException {
0666: return dirContext.getNameInNamespace();
0667: }
0668:
0669: // ----------------------------------------------------- DirContext Methods
0670:
0671: /**
0672: * Retrieves all of the attributes associated with a named object.
0673: *
0674: * @param name the name of the object from which to retrieve attributes
0675: * @return the set of attributes associated with name.
0676: * Returns an empty attribute set if name has no attributes; never null.
0677: * @throws NamingException if a naming exception is encountered
0678: */
0679: public Attributes getAttributes(Name name) throws NamingException {
0680: CacheEntry entry = cacheLookup(name.toString());
0681: if (entry != null) {
0682: if (!entry.exists) {
0683: throw notFoundException;
0684: }
0685: return entry.attributes;
0686: }
0687: Attributes attributes = dirContext
0688: .getAttributes(parseName(name));
0689: if (!(attributes instanceof ResourceAttributes)) {
0690: attributes = new ResourceAttributes(attributes);
0691: }
0692: return attributes;
0693: }
0694:
0695: /**
0696: * Retrieves all of the attributes associated with a named object.
0697: *
0698: * @param name the name of the object from which to retrieve attributes
0699: * @return the set of attributes associated with name
0700: * @throws NamingException if a naming exception is encountered
0701: */
0702: public Attributes getAttributes(String name) throws NamingException {
0703: CacheEntry entry = cacheLookup(name);
0704: if (entry != null) {
0705: if (!entry.exists) {
0706: throw notFoundException;
0707: }
0708: return entry.attributes;
0709: }
0710: Attributes attributes = dirContext
0711: .getAttributes(parseName(name));
0712: if (!(attributes instanceof ResourceAttributes)) {
0713: attributes = new ResourceAttributes(attributes);
0714: }
0715: return attributes;
0716: }
0717:
0718: /**
0719: * Retrieves selected attributes associated with a named object.
0720: * See the class description regarding attribute models, attribute type
0721: * names, and operational attributes.
0722: *
0723: * @param name the name of the object from which to retrieve attributes
0724: * @param attrIds the identifiers of the attributes to retrieve. null
0725: * indicates that all attributes should be retrieved; an empty array
0726: * indicates that none should be retrieved
0727: * @return the requested attributes; never null
0728: * @throws NamingException if a naming exception is encountered
0729: */
0730: public Attributes getAttributes(Name name, String[] attrIds)
0731: throws NamingException {
0732: Attributes attributes = dirContext.getAttributes(
0733: parseName(name), attrIds);
0734: if (!(attributes instanceof ResourceAttributes)) {
0735: attributes = new ResourceAttributes(attributes);
0736: }
0737: return attributes;
0738: }
0739:
0740: /**
0741: * Retrieves selected attributes associated with a named object.
0742: *
0743: * @param name the name of the object from which to retrieve attributes
0744: * @param attrIds the identifiers of the attributes to retrieve. null
0745: * indicates that all attributes should be retrieved; an empty array
0746: * indicates that none should be retrieved
0747: * @return the requested attributes; never null
0748: * @throws NamingException if a naming exception is encountered
0749: */
0750: public Attributes getAttributes(String name, String[] attrIds)
0751: throws NamingException {
0752: Attributes attributes = dirContext.getAttributes(
0753: parseName(name), attrIds);
0754: if (!(attributes instanceof ResourceAttributes)) {
0755: attributes = new ResourceAttributes(attributes);
0756: }
0757: return attributes;
0758: }
0759:
0760: /**
0761: * Modifies the attributes associated with a named object. The order of
0762: * the modifications is not specified. Where possible, the modifications
0763: * are performed atomically.
0764: *
0765: * @param name the name of the object whose attributes will be updated
0766: * @param mod_op the modification operation, one of: ADD_ATTRIBUTE,
0767: * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
0768: * @param attrs the attributes to be used for the modification; may not
0769: * be null
0770: * @throws NamingException if a naming exception is encountered
0771: */
0772: public void modifyAttributes(Name name, int mod_op, Attributes attrs)
0773: throws NamingException {
0774: dirContext.modifyAttributes(parseName(name), mod_op, attrs);
0775: cacheUnload(name.toString());
0776: }
0777:
0778: /**
0779: * Modifies the attributes associated with a named object.
0780: *
0781: * @param name the name of the object whose attributes will be updated
0782: * @param mod_op the modification operation, one of: ADD_ATTRIBUTE,
0783: * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
0784: * @param attrs the attributes to be used for the modification; may not
0785: * be null
0786: * @throws NamingException if a naming exception is encountered
0787: */
0788: public void modifyAttributes(String name, int mod_op,
0789: Attributes attrs) throws NamingException {
0790: dirContext.modifyAttributes(parseName(name), mod_op, attrs);
0791: cacheUnload(name);
0792: }
0793:
0794: /**
0795: * Modifies the attributes associated with a named object using an an
0796: * ordered list of modifications. The modifications are performed in the
0797: * order specified. Each modification specifies a modification operation
0798: * code and an attribute on which to operate. Where possible, the
0799: * modifications are performed atomically.
0800: *
0801: * @param name the name of the object whose attributes will be updated
0802: * @param mods an ordered sequence of modifications to be performed; may
0803: * not be null
0804: * @throws NamingException if a naming exception is encountered
0805: */
0806: public void modifyAttributes(Name name, ModificationItem[] mods)
0807: throws NamingException {
0808: dirContext.modifyAttributes(parseName(name), mods);
0809: cacheUnload(name.toString());
0810: }
0811:
0812: /**
0813: * Modifies the attributes associated with a named object using an an
0814: * ordered list of modifications.
0815: *
0816: * @param name the name of the object whose attributes will be updated
0817: * @param mods an ordered sequence of modifications to be performed; may
0818: * not be null
0819: * @throws NamingException if a naming exception is encountered
0820: */
0821: public void modifyAttributes(String name, ModificationItem[] mods)
0822: throws NamingException {
0823: dirContext.modifyAttributes(parseName(name), mods);
0824: cacheUnload(name);
0825: }
0826:
0827: /**
0828: * Binds a name to an object, along with associated attributes. If attrs
0829: * is null, the resulting binding will have the attributes associated
0830: * with obj if obj is a DirContext, and no attributes otherwise. If attrs
0831: * is non-null, the resulting binding will have attrs as its attributes;
0832: * any attributes associated with obj are ignored.
0833: *
0834: * @param name the name to bind; may not be empty
0835: * @param obj the object to bind; possibly null
0836: * @param attrs the attributes to associate with the binding
0837: * @throws NamingException if a naming exception is encountered
0838: */
0839: public void bind(Name name, Object obj, Attributes attrs)
0840: throws NamingException {
0841: dirContext.bind(parseName(name), obj, attrs);
0842: cacheUnload(name.toString());
0843: }
0844:
0845: /**
0846: * Binds a name to an object, along with associated attributes.
0847: *
0848: * @param name the name to bind; may not be empty
0849: * @param obj the object to bind; possibly null
0850: * @param attrs the attributes to associate with the binding
0851: * @throws NamingException if a naming exception is encountered
0852: */
0853: public void bind(String name, Object obj, Attributes attrs)
0854: throws NamingException {
0855: dirContext.bind(parseName(name), obj, attrs);
0856: cacheUnload(name);
0857: }
0858:
0859: /**
0860: * Binds a name to an object, along with associated attributes,
0861: * overwriting any existing binding. If attrs is null and obj is a
0862: * DirContext, the attributes from obj are used. If attrs is null and obj
0863: * is not a DirContext, any existing attributes associated with the object
0864: * already bound in the directory remain unchanged. If attrs is non-null,
0865: * any existing attributes associated with the object already bound in
0866: * the directory are removed and attrs is associated with the named
0867: * object. If obj is a DirContext and attrs is non-null, the attributes
0868: * of obj are ignored.
0869: *
0870: * @param name the name to bind; may not be empty
0871: * @param obj the object to bind; possibly null
0872: * @param attrs the attributes to associate with the binding
0873: * @throws NamingException if a naming exception is encountered
0874: */
0875: public void rebind(Name name, Object obj, Attributes attrs)
0876: throws NamingException {
0877: dirContext.rebind(parseName(name), obj, attrs);
0878: cacheUnload(name.toString());
0879: }
0880:
0881: /**
0882: * Binds a name to an object, along with associated attributes,
0883: * overwriting any existing binding.
0884: *
0885: * @param name the name to bind; may not be empty
0886: * @param obj the object to bind; possibly null
0887: * @param attrs the attributes to associate with the binding
0888: * @throws NamingException if a naming exception is encountered
0889: */
0890: public void rebind(String name, Object obj, Attributes attrs)
0891: throws NamingException {
0892: dirContext.rebind(parseName(name), obj, attrs);
0893: cacheUnload(name);
0894: }
0895:
0896: /**
0897: * Creates and binds a new context, along with associated attributes.
0898: * This method creates a new subcontext with the given name, binds it in
0899: * the target context (that named by all but terminal atomic component of
0900: * the name), and associates the supplied attributes with the newly
0901: * created object. All intermediate and target contexts must already
0902: * exist. If attrs is null, this method is equivalent to
0903: * Context.createSubcontext().
0904: *
0905: * @param name the name of the context to create; may not be empty
0906: * @param attrs the attributes to associate with the newly created context
0907: * @return the newly created context
0908: * @throws NamingException if a naming exception is encountered
0909: */
0910: public DirContext createSubcontext(Name name, Attributes attrs)
0911: throws NamingException {
0912: DirContext context = dirContext.createSubcontext(
0913: parseName(name), attrs);
0914: cacheUnload(name.toString());
0915: return context;
0916: }
0917:
0918: /**
0919: * Creates and binds a new context, along with associated attributes.
0920: *
0921: * @param name the name of the context to create; may not be empty
0922: * @param attrs the attributes to associate with the newly created context
0923: * @return the newly created context
0924: * @throws NamingException if a naming exception is encountered
0925: */
0926: public DirContext createSubcontext(String name, Attributes attrs)
0927: throws NamingException {
0928: DirContext context = dirContext.createSubcontext(
0929: parseName(name), attrs);
0930: cacheUnload(name);
0931: return context;
0932: }
0933:
0934: /**
0935: * Retrieves the schema associated with the named object. The schema
0936: * describes rules regarding the structure of the namespace and the
0937: * attributes stored within it. The schema specifies what types of
0938: * objects can be added to the directory and where they can be added;
0939: * what mandatory and optional attributes an object can have. The range
0940: * of support for schemas is directory-specific.
0941: *
0942: * @param name the name of the object whose schema is to be retrieved
0943: * @return the schema associated with the context; never null
0944: * @throws NamingException if a naming exception is encountered
0945: */
0946: public DirContext getSchema(Name name) throws NamingException {
0947: return dirContext.getSchema(parseName(name));
0948: }
0949:
0950: /**
0951: * Retrieves the schema associated with the named object.
0952: *
0953: * @param name the name of the object whose schema is to be retrieved
0954: * @return the schema associated with the context; never null
0955: * @throws NamingException if a naming exception is encountered
0956: */
0957: public DirContext getSchema(String name) throws NamingException {
0958: return dirContext.getSchema(parseName(name));
0959: }
0960:
0961: /**
0962: * Retrieves a context containing the schema objects of the named
0963: * object's class definitions.
0964: *
0965: * @param name the name of the object whose object class definition is to
0966: * be retrieved
0967: * @return the DirContext containing the named object's class
0968: * definitions; never null
0969: * @throws NamingException if a naming exception is encountered
0970: */
0971: public DirContext getSchemaClassDefinition(Name name)
0972: throws NamingException {
0973: return dirContext.getSchemaClassDefinition(parseName(name));
0974: }
0975:
0976: /**
0977: * Retrieves a context containing the schema objects of the named
0978: * object's class definitions.
0979: *
0980: * @param name the name of the object whose object class definition is to
0981: * be retrieved
0982: * @return the DirContext containing the named object's class
0983: * definitions; never null
0984: * @throws NamingException if a naming exception is encountered
0985: */
0986: public DirContext getSchemaClassDefinition(String name)
0987: throws NamingException {
0988: return dirContext.getSchemaClassDefinition(parseName(name));
0989: }
0990:
0991: /**
0992: * Searches in a single context for objects that contain a specified set
0993: * of attributes, and retrieves selected attributes. The search is
0994: * performed using the default SearchControls settings.
0995: *
0996: * @param name the name of the context to search
0997: * @param matchingAttributes the attributes to search for. If empty or
0998: * null, all objects in the target context are returned.
0999: * @param attributesToReturn the attributes to return. null indicates
1000: * that all attributes are to be returned; an empty array indicates that
1001: * none are to be returned.
1002: * @return a non-null enumeration of SearchResult objects. Each
1003: * SearchResult contains the attributes identified by attributesToReturn
1004: * and the name of the corresponding object, named relative to the
1005: * context named by name.
1006: * @throws NamingException if a naming exception is encountered
1007: */
1008: public NamingEnumeration search(Name name,
1009: Attributes matchingAttributes, String[] attributesToReturn)
1010: throws NamingException {
1011: return dirContext.search(parseName(name), matchingAttributes,
1012: attributesToReturn);
1013: }
1014:
1015: /**
1016: * Searches in a single context for objects that contain a specified set
1017: * of attributes, and retrieves selected attributes.
1018: *
1019: * @param name the name of the context to search
1020: * @param matchingAttributes the attributes to search for. If empty or
1021: * null, all objects in the target context are returned.
1022: * @param attributesToReturn the attributes to return. null indicates
1023: * that all attributes are to be returned; an empty array indicates that
1024: * none are to be returned.
1025: * @return a non-null enumeration of SearchResult objects. Each
1026: * SearchResult contains the attributes identified by attributesToReturn
1027: * and the name of the corresponding object, named relative to the
1028: * context named by name.
1029: * @throws NamingException if a naming exception is encountered
1030: */
1031: public NamingEnumeration search(String name,
1032: Attributes matchingAttributes, String[] attributesToReturn)
1033: throws NamingException {
1034: return dirContext.search(parseName(name), matchingAttributes,
1035: attributesToReturn);
1036: }
1037:
1038: /**
1039: * Searches in a single context for objects that contain a specified set
1040: * of attributes. This method returns all the attributes of such objects.
1041: * It is equivalent to supplying null as the atributesToReturn parameter
1042: * to the method search(Name, Attributes, String[]).
1043: *
1044: * @param name the name of the context to search
1045: * @param matchingAttributes the attributes to search for. If empty or
1046: * null, all objects in the target context are returned.
1047: * @return a non-null enumeration of SearchResult objects. Each
1048: * SearchResult contains the attributes identified by attributesToReturn
1049: * and the name of the corresponding object, named relative to the
1050: * context named by name.
1051: * @throws NamingException if a naming exception is encountered
1052: */
1053: public NamingEnumeration search(Name name,
1054: Attributes matchingAttributes) throws NamingException {
1055: return dirContext.search(parseName(name), matchingAttributes);
1056: }
1057:
1058: /**
1059: * Searches in a single context for objects that contain a specified set
1060: * of attributes.
1061: *
1062: * @param name the name of the context to search
1063: * @param matchingAttributes the attributes to search for. If empty or
1064: * null, all objects in the target context are returned.
1065: * @return a non-null enumeration of SearchResult objects. Each
1066: * SearchResult contains the attributes identified by attributesToReturn
1067: * and the name of the corresponding object, named relative to the
1068: * context named by name.
1069: * @throws NamingException if a naming exception is encountered
1070: */
1071: public NamingEnumeration search(String name,
1072: Attributes matchingAttributes) throws NamingException {
1073: return dirContext.search(parseName(name), matchingAttributes);
1074: }
1075:
1076: /**
1077: * Searches in the named context or object for entries that satisfy the
1078: * given search filter. Performs the search as specified by the search
1079: * controls.
1080: *
1081: * @param name the name of the context or object to search
1082: * @param filter the filter expression to use for the search; may not be
1083: * null
1084: * @param cons the search controls that control the search. If null,
1085: * the default search controls are used (equivalent to
1086: * (new SearchControls())).
1087: * @return an enumeration of SearchResults of the objects that satisfy
1088: * the filter; never null
1089: * @throws NamingException if a naming exception is encountered
1090: */
1091: public NamingEnumeration search(Name name, String filter,
1092: SearchControls cons) throws NamingException {
1093: return dirContext.search(parseName(name), filter, cons);
1094: }
1095:
1096: /**
1097: * Searches in the named context or object for entries that satisfy the
1098: * given search filter. Performs the search as specified by the search
1099: * controls.
1100: *
1101: * @param name the name of the context or object to search
1102: * @param filter the filter expression to use for the search; may not be
1103: * null
1104: * @param cons the search controls that control the search. If null,
1105: * the default search controls are used (equivalent to
1106: * (new SearchControls())).
1107: * @return an enumeration of SearchResults of the objects that satisfy
1108: * the filter; never null
1109: * @throws NamingException if a naming exception is encountered
1110: */
1111: public NamingEnumeration search(String name, String filter,
1112: SearchControls cons) throws NamingException {
1113: return dirContext.search(parseName(name), filter, cons);
1114: }
1115:
1116: /**
1117: * Searches in the named context or object for entries that satisfy the
1118: * given search filter. Performs the search as specified by the search
1119: * controls.
1120: *
1121: * @param name the name of the context or object to search
1122: * @param filterExpr the filter expression to use for the search.
1123: * The expression may contain variables of the form "{i}" where i is a
1124: * nonnegative integer. May not be null.
1125: * @param filterArgs the array of arguments to substitute for the
1126: * variables in filterExpr. The value of filterArgs[i] will replace each
1127: * occurrence of "{i}". If null, equivalent to an empty array.
1128: * @param cons the search controls that control the search. If null, the
1129: * default search controls are used (equivalent to (new SearchControls())).
1130: * @return an enumeration of SearchResults of the objects that satisy the
1131: * filter; never null
1132: * @throws ArrayIndexOutOfBoundsException if filterExpr contains {i}
1133: * expressions where i is outside the bounds of the array filterArgs
1134: * @throws NamingException if a naming exception is encountered
1135: */
1136: public NamingEnumeration search(Name name, String filterExpr,
1137: Object[] filterArgs, SearchControls cons)
1138: throws NamingException {
1139: return dirContext.search(parseName(name), filterExpr,
1140: filterArgs, cons);
1141: }
1142:
1143: /**
1144: * Searches in the named context or object for entries that satisfy the
1145: * given search filter. Performs the search as specified by the search
1146: * controls.
1147: *
1148: * @param name the name of the context or object to search
1149: * @param filterExpr the filter expression to use for the search.
1150: * The expression may contain variables of the form "{i}" where i is a
1151: * nonnegative integer. May not be null.
1152: * @param filterArgs the array of arguments to substitute for the
1153: * variables in filterExpr. The value of filterArgs[i] will replace each
1154: * occurrence of "{i}". If null, equivalent to an empty array.
1155: * @param cons the search controls that control the search. If null, the
1156: * default search controls are used (equivalent to (new SearchControls())).
1157: * @return an enumeration of SearchResults of the objects that satisy the
1158: * filter; never null
1159: * @throws ArrayIndexOutOfBoundsException if filterExpr contains {i}
1160: * expressions where i is outside the bounds of the array filterArgs
1161: * @throws NamingException if a naming exception is encountered
1162: */
1163: public NamingEnumeration search(String name, String filterExpr,
1164: Object[] filterArgs, SearchControls cons)
1165: throws NamingException {
1166: return dirContext.search(parseName(name), filterExpr,
1167: filterArgs, cons);
1168: }
1169:
1170: // --------------------------------------------------------- Public Methods
1171:
1172: /**
1173: * Retrieves the named object as a cache entry, without any exception.
1174: *
1175: * @param name the name of the object to look up
1176: * @return the cache entry bound to name
1177: */
1178: public CacheEntry lookupCache(String name) {
1179: CacheEntry entry = cacheLookup(name);
1180: if (entry == null) {
1181: entry = new CacheEntry();
1182: entry.name = name;
1183: try {
1184: Object object = dirContext.lookup(parseName(name));
1185: if (object instanceof InputStream) {
1186: entry.resource = new Resource((InputStream) object);
1187: } else if (object instanceof DirContext) {
1188: entry.context = (DirContext) object;
1189: } else if (object instanceof Resource) {
1190: entry.resource = (Resource) object;
1191: } else {
1192: entry.resource = new Resource(
1193: new ByteArrayInputStream(FxSharedUtils
1194: .getBytes(object.toString())));
1195: }
1196: Attributes attributes = dirContext
1197: .getAttributes(parseName(name));
1198: if (!(attributes instanceof ResourceAttributes)) {
1199: attributes = new ResourceAttributes(attributes);
1200: }
1201: entry.attributes = (ResourceAttributes) attributes;
1202: } catch (NamingException e) {
1203: entry.exists = false;
1204: }
1205: }
1206: return entry;
1207: }
1208:
1209: // ------------------------------------------------------ Protected Methods
1210:
1211: /**
1212: * Parses a name.
1213: *
1214: * @return the parsed name
1215: */
1216: protected String parseName(String name) throws NamingException {
1217: return name;
1218: }
1219:
1220: /**
1221: * Parses a name.
1222: *
1223: * @return the parsed name
1224: */
1225: protected Name parseName(Name name) throws NamingException {
1226: return name;
1227: }
1228:
1229: /**
1230: * Lookup in cache.
1231: */
1232: protected CacheEntry cacheLookup(String name) {
1233: if (cache == null)
1234: return (null);
1235: if (name == null)
1236: name = "";
1237: for (int i = 0; i < nonCacheable.length; i++) {
1238: if (name.startsWith(nonCacheable[i])) {
1239: return (null);
1240: }
1241: }
1242: CacheEntry cacheEntry = cache.lookup(name);
1243: if (cacheEntry == null) {
1244: cacheEntry = new CacheEntry();
1245: cacheEntry.name = name;
1246: // Load entry
1247: cacheLoad(cacheEntry);
1248: } else {
1249: if (!validate(cacheEntry)) {
1250: if (!revalidate(cacheEntry)) {
1251: cacheUnload(cacheEntry.name);
1252: return (null);
1253: } else {
1254: cacheEntry.timestamp = System.currentTimeMillis()
1255: + cacheTTL;
1256: }
1257: }
1258: cacheEntry.accessCount++;
1259: }
1260: return (cacheEntry);
1261: }
1262:
1263: /**
1264: * Validate entry.
1265: */
1266: protected boolean validate(CacheEntry entry) {
1267: if (((!entry.exists) || (entry.context != null) || ((entry.resource != null) && (entry.resource
1268: .getContent() != null)))
1269: && (System.currentTimeMillis() < entry.timestamp)) {
1270: return true;
1271: }
1272: return false;
1273: }
1274:
1275: /**
1276: * Revalidate entry.
1277: */
1278: protected boolean revalidate(CacheEntry entry) {
1279: // Get the attributes at the given path, and check the last
1280: // modification date
1281: if (!entry.exists)
1282: return false;
1283: if (entry.attributes == null)
1284: return false;
1285: long lastModified = entry.attributes.getLastModified();
1286: long contentLength = entry.attributes.getContentLength();
1287: if (lastModified <= 0)
1288: return false;
1289: try {
1290: Attributes tempAttributes = dirContext
1291: .getAttributes(entry.name);
1292: ResourceAttributes attributes = null;
1293: if (!(tempAttributes instanceof ResourceAttributes)) {
1294: attributes = new ResourceAttributes(tempAttributes);
1295: } else {
1296: attributes = (ResourceAttributes) tempAttributes;
1297: }
1298: long lastModified2 = attributes.getLastModified();
1299: long contentLength2 = attributes.getContentLength();
1300: return (lastModified == lastModified2)
1301: && (contentLength == contentLength2);
1302: } catch (NamingException e) {
1303: return false;
1304: }
1305: }
1306:
1307: /**
1308: * Load entry into cache.
1309: */
1310: protected void cacheLoad(CacheEntry entry) {
1311:
1312: String name = entry.name;
1313:
1314: // Retrieve missing info
1315: boolean exists = true;
1316:
1317: // Retrieving attributes
1318: if (entry.attributes == null) {
1319: try {
1320: Attributes attributes = dirContext
1321: .getAttributes(entry.name);
1322: if (!(attributes instanceof ResourceAttributes)) {
1323: entry.attributes = new ResourceAttributes(
1324: attributes);
1325: } else {
1326: entry.attributes = (ResourceAttributes) attributes;
1327: }
1328: } catch (NamingException e) {
1329: exists = false;
1330: }
1331: }
1332:
1333: // Retriving object
1334: if ((exists) && (entry.resource == null)
1335: && (entry.context == null)) {
1336: try {
1337: Object object = dirContext.lookup(name);
1338: if (object instanceof InputStream) {
1339: entry.resource = new Resource((InputStream) object);
1340: } else if (object instanceof DirContext) {
1341: entry.context = (DirContext) object;
1342: } else if (object instanceof Resource) {
1343: entry.resource = (Resource) object;
1344: } else {
1345: entry.resource = new Resource(
1346: new ByteArrayInputStream(FxSharedUtils
1347: .getBytes(object.toString())));
1348: }
1349: } catch (NamingException e) {
1350: exists = false;
1351: }
1352: }
1353:
1354: // Load object content
1355: if ((exists)
1356: && (entry.resource != null)
1357: && (entry.resource.getContent() == null)
1358: && (entry.attributes.getContentLength() >= 0)
1359: && (entry.attributes.getContentLength() < (cacheObjectMaxSize * 1024))) {
1360: int length = (int) entry.attributes.getContentLength();
1361: // The entry size is 1 + the resource size in KB, if it will be
1362: // cached
1363: entry.size += (entry.attributes.getContentLength() / 1024);
1364: InputStream is = null;
1365: try {
1366: is = entry.resource.streamContent();
1367: int pos = 0;
1368: byte[] b = new byte[length];
1369: while (pos < length) {
1370: int n = is.read(b, pos, length - pos);
1371: if (n < 0)
1372: break;
1373: pos = pos + n;
1374: }
1375: entry.resource.setContent(b);
1376: } catch (IOException e) {
1377: ; // Ignore
1378: } finally {
1379: try {
1380: if (is != null)
1381: is.close();
1382: } catch (IOException e) {
1383: ; // Ignore
1384: }
1385: }
1386: }
1387:
1388: // Set existence flag
1389: entry.exists = exists;
1390:
1391: // Set timestamp
1392: entry.timestamp = System.currentTimeMillis() + cacheTTL;
1393:
1394: // Add new entry to cache
1395: synchronized (cache) {
1396: // Check cache size, and remove elements if too big
1397: if ((cache.lookup(name) == null)
1398: && cache.allocate(entry.size)) {
1399: cache.load(entry);
1400: }
1401: }
1402:
1403: }
1404:
1405: /**
1406: * Remove entry from cache.
1407: */
1408: protected boolean cacheUnload(String name) {
1409: if (cache == null)
1410: return false;
1411: synchronized (cache) {
1412: return cache.unload(name);
1413: }
1414: }
1415:
1416: }
|