0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/naming/resources/FileDirContext.java,v 1.13 2002/03/17 00:03:13 remm Exp $
0003: * $Revision: 1.13 $
0004: * $Date: 2002/03/17 00:03:13 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999 The Apache Software Foundation. All rights
0011: * reserved.
0012: *
0013: * Redistribution and use in source and binary forms, with or without
0014: * modification, are permitted provided that the following conditions
0015: * are met:
0016: *
0017: * 1. Redistributions of source code must retain the above copyright
0018: * notice, this list of conditions and the following disclaimer.
0019: *
0020: * 2. Redistributions in binary form must reproduce the above copyright
0021: * notice, this list of conditions and the following disclaimer in
0022: * the documentation and/or other materials provided with the
0023: * distribution.
0024: *
0025: * 3. The end-user documentation included with the redistribution, if
0026: * any, must include the following acknowlegement:
0027: * "This product includes software developed by the
0028: * Apache Software Foundation (http://www.apache.org/)."
0029: * Alternately, this acknowlegement may appear in the software itself,
0030: * if and wherever such third-party acknowlegements normally appear.
0031: *
0032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033: * Foundation" must not be used to endorse or promote products derived
0034: * from this software without prior written permission. For written
0035: * permission, please contact apache@apache.org.
0036: *
0037: * 5. Products derived from this software may not be called "Apache"
0038: * nor may "Apache" appear in their names without prior written
0039: * permission of the Apache Group.
0040: *
0041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052: * SUCH DAMAGE.
0053: * ====================================================================
0054: *
0055: * This software consists of voluntary contributions made by many
0056: * individuals on behalf of the Apache Software Foundation. For more
0057: * information on the Apache Software Foundation, please see
0058: * <http://www.apache.org/>.
0059: *
0060: * [Additional notices, if required by prior licensing conditions]
0061: *
0062: */
0063:
0064: package org.apache.naming.resources;
0065:
0066: import java.util.Arrays;
0067: import java.util.Hashtable;
0068: import java.util.Vector;
0069: import java.util.Date;
0070: import java.io.File;
0071: import java.io.FileInputStream;
0072: import java.io.InputStream;
0073: import java.io.FileOutputStream;
0074: import java.io.FileNotFoundException;
0075: import java.io.OutputStream;
0076: import java.io.IOException;
0077: import javax.naming.Context;
0078: import javax.naming.Name;
0079: import javax.naming.NameParser;
0080: import javax.naming.NamingEnumeration;
0081: import javax.naming.NamingException;
0082: import javax.naming.CompositeName;
0083: import javax.naming.NameParser;
0084: import javax.naming.OperationNotSupportedException;
0085: import javax.naming.NameAlreadyBoundException;
0086: import javax.naming.directory.DirContext;
0087: import javax.naming.directory.Attributes;
0088: import javax.naming.directory.Attribute;
0089: import javax.naming.directory.ModificationItem;
0090: import javax.naming.directory.SearchControls;
0091: import org.apache.naming.StringManager;
0092: import org.apache.naming.NameParserImpl;
0093: import org.apache.naming.NamingEntry;
0094: import org.apache.naming.NamingContextBindingsEnumeration;
0095: import org.apache.naming.NamingContextEnumeration;
0096:
0097: /**
0098: * Filesystem Directory Context implementation helper class.
0099: *
0100: * @author Remy Maucherat
0101: * @version $Revision: 1.13 $ $Date: 2002/03/17 00:03:13 $
0102: */
0103:
0104: public class FileDirContext extends BaseDirContext {
0105:
0106: // -------------------------------------------------------------- Constants
0107:
0108: /**
0109: * The descriptive information string for this implementation.
0110: */
0111: protected static final int BUFFER_SIZE = 2048;
0112:
0113: // ----------------------------------------------------------- Constructors
0114:
0115: /**
0116: * Builds a file directory context using the given environment.
0117: */
0118: public FileDirContext() {
0119: super ();
0120: }
0121:
0122: /**
0123: * Builds a file directory context using the given environment.
0124: */
0125: public FileDirContext(Hashtable env) {
0126: super (env);
0127: }
0128:
0129: // ----------------------------------------------------- Instance Variables
0130:
0131: /**
0132: * The document base directory.
0133: */
0134: protected File base = null;
0135:
0136: /**
0137: * Absolute normalized filename of the base.
0138: */
0139: protected String absoluteBase = null;
0140:
0141: /**
0142: * Case sensitivity.
0143: */
0144: protected boolean caseSensitive = true;
0145:
0146: // ------------------------------------------------------------- Properties
0147:
0148: /**
0149: * Set the document root.
0150: *
0151: * @param docBase The new document root
0152: *
0153: * @exception IllegalArgumentException if the specified value is not
0154: * supported by this implementation
0155: * @exception IllegalArgumentException if this would create a
0156: * malformed URL
0157: */
0158: public void setDocBase(String docBase) {
0159:
0160: // Validate the format of the proposed document root
0161: if (docBase == null)
0162: throw new IllegalArgumentException(sm
0163: .getString("resources.null"));
0164:
0165: // Calculate a File object referencing this document base directory
0166: base = new File(docBase);
0167: try {
0168: base = base.getCanonicalFile();
0169: } catch (IOException e) {
0170: // Ignore
0171: }
0172:
0173: // Validate that the document base is an existing directory
0174: if (!base.exists() || !base.isDirectory() || !base.canRead())
0175: throw new IllegalArgumentException(sm.getString(
0176: "fileResources.base", docBase));
0177: this .absoluteBase = base.getAbsolutePath();
0178: super .setDocBase(docBase);
0179:
0180: }
0181:
0182: /**
0183: * Set case sensitivity.
0184: */
0185: public void setCaseSensitive(boolean caseSensitive) {
0186: this .caseSensitive = caseSensitive;
0187: }
0188:
0189: /**
0190: * Is case sensitive ?
0191: */
0192: public boolean isCaseSensitive() {
0193: return caseSensitive;
0194: }
0195:
0196: // --------------------------------------------------------- Public Methods
0197:
0198: /**
0199: * Release any resources allocated for this directory context.
0200: */
0201: public void release() {
0202:
0203: caseSensitive = true;
0204: absoluteBase = null;
0205: base = null;
0206: super .release();
0207:
0208: }
0209:
0210: // -------------------------------------------------------- Context Methods
0211:
0212: /**
0213: * Retrieves the named object.
0214: *
0215: * @param name the name of the object to look up
0216: * @return the object bound to name
0217: * @exception NamingException if a naming exception is encountered
0218: */
0219: public Object lookup(String name) throws NamingException {
0220: Object result = null;
0221: File file = file(name);
0222:
0223: if (file == null)
0224: throw new NamingException(sm.getString(
0225: "resources.notFound", name));
0226:
0227: if (file.isDirectory()) {
0228: FileDirContext tempContext = new FileDirContext(env);
0229: tempContext.setDocBase(file.getPath());
0230: result = tempContext;
0231: } else {
0232: result = new FileResource(file);
0233: }
0234:
0235: return result;
0236:
0237: }
0238:
0239: /**
0240: * Unbinds the named object. Removes the terminal atomic name in name
0241: * from the target context--that named by all but the terminal atomic
0242: * part of name.
0243: * <p>
0244: * This method is idempotent. It succeeds even if the terminal atomic
0245: * name is not bound in the target context, but throws
0246: * NameNotFoundException if any of the intermediate contexts do not exist.
0247: *
0248: * @param name the name to bind; may not be empty
0249: * @exception NameNotFoundException if an intermediate context does not
0250: * exist
0251: * @exception NamingException if a naming exception is encountered
0252: */
0253: public void unbind(String name) throws NamingException {
0254:
0255: File file = file(name);
0256:
0257: if (file == null)
0258: throw new NamingException(sm.getString(
0259: "resources.notFound", name));
0260:
0261: if (!file.delete())
0262: throw new NamingException(sm.getString(
0263: "resources.unbindFailed", name));
0264:
0265: }
0266:
0267: /**
0268: * Binds a new name to the object bound to an old name, and unbinds the
0269: * old name. Both names are relative to this context. Any attributes
0270: * associated with the old name become associated with the new name.
0271: * Intermediate contexts of the old name are not changed.
0272: *
0273: * @param oldName the name of the existing binding; may not be empty
0274: * @param newName the name of the new binding; may not be empty
0275: * @exception NameAlreadyBoundException if newName is already bound
0276: * @exception NamingException if a naming exception is encountered
0277: */
0278: public void rename(String oldName, String newName)
0279: throws NamingException {
0280:
0281: File file = file(oldName);
0282:
0283: if (file == null)
0284: throw new NamingException(sm.getString(
0285: "resources.notFound", oldName));
0286:
0287: File newFile = new File(base, newName);
0288:
0289: file.renameTo(newFile);
0290:
0291: }
0292:
0293: /**
0294: * Enumerates the names bound in the named context, along with the class
0295: * names of objects bound to them. The contents of any subcontexts are
0296: * not included.
0297: * <p>
0298: * If a binding is added to or removed from this context, its effect on
0299: * an enumeration previously returned is undefined.
0300: *
0301: * @param name the name of the context to list
0302: * @return an enumeration of the names and class names of the bindings in
0303: * this context. Each element of the enumeration is of type NameClassPair.
0304: * @exception NamingException if a naming exception is encountered
0305: */
0306: public NamingEnumeration list(String name) throws NamingException {
0307:
0308: File file = file(name);
0309:
0310: if (file == null)
0311: throw new NamingException(sm.getString(
0312: "resources.notFound", name));
0313:
0314: Vector entries = list(file);
0315:
0316: return new NamingContextEnumeration(entries);
0317:
0318: }
0319:
0320: /**
0321: * Enumerates the names bound in the named context, along with the
0322: * objects bound to them. The contents of any subcontexts are not
0323: * included.
0324: * <p>
0325: * If a binding is added to or removed from this context, its effect on
0326: * an enumeration previously returned is undefined.
0327: *
0328: * @param name the name of the context to list
0329: * @return an enumeration of the bindings in this context.
0330: * Each element of the enumeration is of type Binding.
0331: * @exception NamingException if a naming exception is encountered
0332: */
0333: public NamingEnumeration listBindings(String name)
0334: throws NamingException {
0335:
0336: File file = file(name);
0337:
0338: if (file == null)
0339: throw new NamingException(sm.getString(
0340: "resources.notFound", name));
0341:
0342: Vector entries = list(file);
0343:
0344: return new NamingContextBindingsEnumeration(entries);
0345:
0346: }
0347:
0348: /**
0349: * Destroys the named context and removes it from the namespace. Any
0350: * attributes associated with the name are also removed. Intermediate
0351: * contexts are not destroyed.
0352: * <p>
0353: * This method is idempotent. It succeeds even if the terminal atomic
0354: * name is not bound in the target context, but throws
0355: * NameNotFoundException if any of the intermediate contexts do not exist.
0356: *
0357: * In a federated naming system, a context from one naming system may be
0358: * bound to a name in another. One can subsequently look up and perform
0359: * operations on the foreign context using a composite name. However, an
0360: * attempt destroy the context using this composite name will fail with
0361: * NotContextException, because the foreign context is not a "subcontext"
0362: * of the context in which it is bound. Instead, use unbind() to remove
0363: * the binding of the foreign context. Destroying the foreign context
0364: * requires that the destroySubcontext() be performed on a context from
0365: * the foreign context's "native" naming system.
0366: *
0367: * @param name the name of the context to be destroyed; may not be empty
0368: * @exception NameNotFoundException if an intermediate context does not
0369: * exist
0370: * @exception NotContextException if the name is bound but does not name
0371: * a context, or does not name a context of the appropriate type
0372: */
0373: public void destroySubcontext(String name) throws NamingException {
0374: unbind(name);
0375: }
0376:
0377: /**
0378: * Retrieves the named object, following links except for the terminal
0379: * atomic component of the name. If the object bound to name is not a
0380: * link, returns the object itself.
0381: *
0382: * @param name the name of the object to look up
0383: * @return the object bound to name, not following the terminal link
0384: * (if any).
0385: * @exception NamingException if a naming exception is encountered
0386: */
0387: public Object lookupLink(String name) throws NamingException {
0388: // Note : Links are not supported
0389: return lookup(name);
0390: }
0391:
0392: /**
0393: * Retrieves the full name of this context within its own namespace.
0394: * <p>
0395: * Many naming services have a notion of a "full name" for objects in
0396: * their respective namespaces. For example, an LDAP entry has a
0397: * distinguished name, and a DNS record has a fully qualified name. This
0398: * method allows the client application to retrieve this name. The string
0399: * returned by this method is not a JNDI composite name and should not be
0400: * passed directly to context methods. In naming systems for which the
0401: * notion of full name does not make sense,
0402: * OperationNotSupportedException is thrown.
0403: *
0404: * @return this context's name in its own namespace; never null
0405: * @exception OperationNotSupportedException if the naming system does
0406: * not have the notion of a full name
0407: * @exception NamingException if a naming exception is encountered
0408: */
0409: public String getNameInNamespace() throws NamingException {
0410: return docBase;
0411: }
0412:
0413: // ----------------------------------------------------- DirContext Methods
0414:
0415: /**
0416: * Retrieves selected attributes associated with a named object.
0417: * See the class description regarding attribute models, attribute type
0418: * names, and operational attributes.
0419: *
0420: * @return the requested attributes; never null
0421: * @param name the name of the object from which to retrieve attributes
0422: * @param attrIds the identifiers of the attributes to retrieve. null
0423: * indicates that all attributes should be retrieved; an empty array
0424: * indicates that none should be retrieved
0425: * @exception NamingException if a naming exception is encountered
0426: */
0427: public Attributes getAttributes(String name, String[] attrIds)
0428: throws NamingException {
0429:
0430: // Building attribute list
0431: File file = file(name);
0432:
0433: if (file == null)
0434: throw new NamingException(sm.getString(
0435: "resources.notFound", name));
0436:
0437: return new FileResourceAttributes(file);
0438:
0439: }
0440:
0441: /**
0442: * Modifies the attributes associated with a named object. The order of
0443: * the modifications is not specified. Where possible, the modifications
0444: * are performed atomically.
0445: *
0446: * @param name the name of the object whose attributes will be updated
0447: * @param mod_op the modification operation, one of: ADD_ATTRIBUTE,
0448: * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
0449: * @param attrs the attributes to be used for the modification; may not
0450: * be null
0451: * @exception AttributeModificationException if the modification cannot be
0452: * completed successfully
0453: * @exception NamingException if a naming exception is encountered
0454: */
0455: public void modifyAttributes(String name, int mod_op,
0456: Attributes attrs) throws NamingException {
0457:
0458: }
0459:
0460: /**
0461: * Modifies the attributes associated with a named object using an an
0462: * ordered list of modifications. The modifications are performed in the
0463: * order specified. Each modification specifies a modification operation
0464: * code and an attribute on which to operate. Where possible, the
0465: * modifications are performed atomically.
0466: *
0467: * @param name the name of the object whose attributes will be updated
0468: * @param mods an ordered sequence of modifications to be performed; may
0469: * not be null
0470: * @exception AttributeModificationException if the modification cannot be
0471: * completed successfully
0472: * @exception NamingException if a naming exception is encountered
0473: */
0474: public void modifyAttributes(String name, ModificationItem[] mods)
0475: throws NamingException {
0476:
0477: }
0478:
0479: /**
0480: * Binds a name to an object, along with associated attributes. If attrs
0481: * is null, the resulting binding will have the attributes associated
0482: * with obj if obj is a DirContext, and no attributes otherwise. If attrs
0483: * is non-null, the resulting binding will have attrs as its attributes;
0484: * any attributes associated with obj are ignored.
0485: *
0486: * @param name the name to bind; may not be empty
0487: * @param obj the object to bind; possibly null
0488: * @param attrs the attributes to associate with the binding
0489: * @exception NameAlreadyBoundException if name is already bound
0490: * @exception InvalidAttributesException if some "mandatory" attributes
0491: * of the binding are not supplied
0492: * @exception NamingException if a naming exception is encountered
0493: */
0494: public void bind(String name, Object obj, Attributes attrs)
0495: throws NamingException {
0496:
0497: // Note: No custom attributes allowed
0498:
0499: File file = new File(base, name);
0500: if (file.exists())
0501: throw new NameAlreadyBoundException(sm.getString(
0502: "resources.alreadyBound", name));
0503:
0504: rebind(name, obj, attrs);
0505:
0506: }
0507:
0508: /**
0509: * Binds a name to an object, along with associated attributes,
0510: * overwriting any existing binding. If attrs is null and obj is a
0511: * DirContext, the attributes from obj are used. If attrs is null and obj
0512: * is not a DirContext, any existing attributes associated with the object
0513: * already bound in the directory remain unchanged. If attrs is non-null,
0514: * any existing attributes associated with the object already bound in
0515: * the directory are removed and attrs is associated with the named
0516: * object. If obj is a DirContext and attrs is non-null, the attributes
0517: * of obj are ignored.
0518: *
0519: * @param name the name to bind; may not be empty
0520: * @param obj the object to bind; possibly null
0521: * @param attrs the attributes to associate with the binding
0522: * @exception InvalidAttributesException if some "mandatory" attributes
0523: * of the binding are not supplied
0524: * @exception NamingException if a naming exception is encountered
0525: */
0526: public void rebind(String name, Object obj, Attributes attrs)
0527: throws NamingException {
0528:
0529: // Note: No custom attributes allowed
0530: // Check obj type
0531:
0532: File file = new File(base, name);
0533:
0534: InputStream is = null;
0535: if (obj instanceof Resource) {
0536: try {
0537: is = ((Resource) obj).streamContent();
0538: } catch (IOException e) {
0539: }
0540: } else if (obj instanceof InputStream) {
0541: is = (InputStream) obj;
0542: } else if (obj instanceof DirContext) {
0543: if (file.exists()) {
0544: if (!file.delete())
0545: throw new NamingException(sm.getString(
0546: "resources.bindFailed", name));
0547: }
0548: if (!file.mkdir())
0549: throw new NamingException(sm.getString(
0550: "resources.bindFailed", name));
0551: }
0552: if (is == null)
0553: throw new NamingException(sm.getString(
0554: "resources.bindFailed", name));
0555:
0556: // Open os
0557:
0558: try {
0559: FileOutputStream os = null;
0560: byte buffer[] = new byte[BUFFER_SIZE];
0561: int len = -1;
0562: try {
0563: os = new FileOutputStream(file);
0564: while (true) {
0565: len = is.read(buffer);
0566: if (len == -1)
0567: break;
0568: os.write(buffer, 0, len);
0569: }
0570: } finally {
0571: if (os != null)
0572: os.close();
0573: is.close();
0574: }
0575: } catch (IOException e) {
0576: throw new NamingException(sm.getString(
0577: "resources.bindFailed", e));
0578: }
0579:
0580: }
0581:
0582: /**
0583: * Creates and binds a new context, along with associated attributes.
0584: * This method creates a new subcontext with the given name, binds it in
0585: * the target context (that named by all but terminal atomic component of
0586: * the name), and associates the supplied attributes with the newly
0587: * created object. All intermediate and target contexts must already
0588: * exist. If attrs is null, this method is equivalent to
0589: * Context.createSubcontext().
0590: *
0591: * @param name the name of the context to create; may not be empty
0592: * @param attrs the attributes to associate with the newly created context
0593: * @return the newly created context
0594: * @exception NameAlreadyBoundException if the name is already bound
0595: * @exception InvalidAttributesException if attrs does not contain all
0596: * the mandatory attributes required for creation
0597: * @exception NamingException if a naming exception is encountered
0598: */
0599: public DirContext createSubcontext(String name, Attributes attrs)
0600: throws NamingException {
0601:
0602: File file = new File(base, name);
0603: if (file.exists())
0604: throw new NameAlreadyBoundException(sm.getString(
0605: "resources.alreadyBound", name));
0606: if (!file.mkdir())
0607: throw new NamingException(sm.getString(
0608: "resources.bindFailed", name));
0609: return (DirContext) lookup(name);
0610:
0611: }
0612:
0613: /**
0614: * Retrieves the schema associated with the named object. The schema
0615: * describes rules regarding the structure of the namespace and the
0616: * attributes stored within it. The schema specifies what types of
0617: * objects can be added to the directory and where they can be added;
0618: * what mandatory and optional attributes an object can have. The range
0619: * of support for schemas is directory-specific.
0620: *
0621: * @param name the name of the object whose schema is to be retrieved
0622: * @return the schema associated with the context; never null
0623: * @exception OperationNotSupportedException if schema not supported
0624: * @exception NamingException if a naming exception is encountered
0625: */
0626: public DirContext getSchema(String name) throws NamingException {
0627: throw new OperationNotSupportedException();
0628: }
0629:
0630: /**
0631: * Retrieves a context containing the schema objects of the named
0632: * object's class definitions.
0633: *
0634: * @param name the name of the object whose object class definition is to
0635: * be retrieved
0636: * @return the DirContext containing the named object's class
0637: * definitions; never null
0638: * @exception OperationNotSupportedException if schema not supported
0639: * @exception NamingException if a naming exception is encountered
0640: */
0641: public DirContext getSchemaClassDefinition(String name)
0642: throws NamingException {
0643: throw new OperationNotSupportedException();
0644: }
0645:
0646: /**
0647: * Searches in a single context for objects that contain a specified set
0648: * of attributes, and retrieves selected attributes. The search is
0649: * performed using the default SearchControls settings.
0650: *
0651: * @param name the name of the context to search
0652: * @param matchingAttributes the attributes to search for. If empty or
0653: * null, all objects in the target context are returned.
0654: * @param attributesToReturn the attributes to return. null indicates
0655: * that all attributes are to be returned; an empty array indicates that
0656: * none are to be returned.
0657: * @return a non-null enumeration of SearchResult objects. Each
0658: * SearchResult contains the attributes identified by attributesToReturn
0659: * and the name of the corresponding object, named relative to the
0660: * context named by name.
0661: * @exception NamingException if a naming exception is encountered
0662: */
0663: public NamingEnumeration search(String name,
0664: Attributes matchingAttributes, String[] attributesToReturn)
0665: throws NamingException {
0666: return null;
0667: }
0668:
0669: /**
0670: * Searches in a single context for objects that contain a specified set
0671: * of attributes. This method returns all the attributes of such objects.
0672: * It is equivalent to supplying null as the atributesToReturn parameter
0673: * to the method search(Name, Attributes, String[]).
0674: *
0675: * @param name the name of the context to search
0676: * @param matchingAttributes the attributes to search for. If empty or
0677: * null, all objects in the target context are returned.
0678: * @return a non-null enumeration of SearchResult objects. Each
0679: * SearchResult contains the attributes identified by attributesToReturn
0680: * and the name of the corresponding object, named relative to the
0681: * context named by name.
0682: * @exception NamingException if a naming exception is encountered
0683: */
0684: public NamingEnumeration search(String name,
0685: Attributes matchingAttributes) throws NamingException {
0686: return null;
0687: }
0688:
0689: /**
0690: * Searches in the named context or object for entries that satisfy the
0691: * given search filter. Performs the search as specified by the search
0692: * controls.
0693: *
0694: * @param name the name of the context or object to search
0695: * @param filter the filter expression to use for the search; may not be
0696: * null
0697: * @param cons the search controls that control the search. If null,
0698: * the default search controls are used (equivalent to
0699: * (new SearchControls())).
0700: * @return an enumeration of SearchResults of the objects that satisfy
0701: * the filter; never null
0702: * @exception InvalidSearchFilterException if the search filter specified
0703: * is not supported or understood by the underlying directory
0704: * @exception InvalidSearchControlsException if the search controls
0705: * contain invalid settings
0706: * @exception NamingException if a naming exception is encountered
0707: */
0708: public NamingEnumeration search(String name, String filter,
0709: SearchControls cons) throws NamingException {
0710: return null;
0711: }
0712:
0713: /**
0714: * Searches in the named context or object for entries that satisfy the
0715: * given search filter. Performs the search as specified by the search
0716: * controls.
0717: *
0718: * @param name the name of the context or object to search
0719: * @param filterExpr the filter expression to use for the search.
0720: * The expression may contain variables of the form "{i}" where i is a
0721: * nonnegative integer. May not be null.
0722: * @param filterArgs the array of arguments to substitute for the
0723: * variables in filterExpr. The value of filterArgs[i] will replace each
0724: * occurrence of "{i}". If null, equivalent to an empty array.
0725: * @param cons the search controls that control the search. If null, the
0726: * default search controls are used (equivalent to (new SearchControls())).
0727: * @return an enumeration of SearchResults of the objects that satisy the
0728: * filter; never null
0729: * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i}
0730: * expressions where i is outside the bounds of the array filterArgs
0731: * @exception InvalidSearchControlsException if cons contains invalid
0732: * settings
0733: * @exception InvalidSearchFilterException if filterExpr with filterArgs
0734: * represents an invalid search filter
0735: * @exception NamingException if a naming exception is encountered
0736: */
0737: public NamingEnumeration search(String name, String filterExpr,
0738: Object[] filterArgs, SearchControls cons)
0739: throws NamingException {
0740: return null;
0741: }
0742:
0743: // ------------------------------------------------------ Protected Methods
0744:
0745: /**
0746: * Return a context-relative path, beginning with a "/", that represents
0747: * the canonical version of the specified path after ".." and "." elements
0748: * are resolved out. If the specified path attempts to go outside the
0749: * boundaries of the current context (i.e. too many ".." path elements
0750: * are present), return <code>null</code> instead.
0751: *
0752: * @param path Path to be normalized
0753: */
0754: protected String normalize(String path) {
0755:
0756: String normalized = path;
0757:
0758: // Normalize the slashes and add leading slash if necessary
0759: if (normalized.indexOf('\\') >= 0)
0760: normalized = normalized.replace('\\', '/');
0761: if (!normalized.startsWith("/"))
0762: normalized = "/" + normalized;
0763:
0764: // Resolve occurrences of "//" in the normalized path
0765: while (true) {
0766: int index = normalized.indexOf("//");
0767: if (index < 0)
0768: break;
0769: normalized = normalized.substring(0, index)
0770: + normalized.substring(index + 1);
0771: }
0772:
0773: // Resolve occurrences of "/./" in the normalized path
0774: while (true) {
0775: int index = normalized.indexOf("/./");
0776: if (index < 0)
0777: break;
0778: normalized = normalized.substring(0, index)
0779: + normalized.substring(index + 2);
0780: }
0781:
0782: // Resolve occurrences of "/../" in the normalized path
0783: while (true) {
0784: int index = normalized.indexOf("/../");
0785: if (index < 0)
0786: break;
0787: if (index == 0)
0788: return (null); // Trying to go outside our context
0789: int index2 = normalized.lastIndexOf('/', index - 1);
0790: normalized = normalized.substring(0, index2)
0791: + normalized.substring(index + 3);
0792: }
0793:
0794: // Return the normalized path that we have completed
0795: return (normalized);
0796:
0797: }
0798:
0799: /**
0800: * Return a File object representing the specified normalized
0801: * context-relative path if it exists and is readable. Otherwise,
0802: * return <code>null</code>.
0803: *
0804: * @param name Normalized context-relative path (with leading '/')
0805: */
0806: protected File file(String name) {
0807:
0808: File file = new File(base, name);
0809: if (file.exists() && file.canRead()) {
0810:
0811: // Check that this file belongs to our root path
0812: String canPath = null;
0813: try {
0814: canPath = file.getCanonicalPath();
0815: } catch (IOException e) {
0816: }
0817: if (canPath == null)
0818: return null;
0819:
0820: if (!canPath.startsWith(absoluteBase)) {
0821: return null;
0822: }
0823:
0824: // Windows only check
0825: if ((caseSensitive) && (File.separatorChar == '\\')) {
0826: String fileAbsPath = file.getAbsolutePath();
0827: if (fileAbsPath.endsWith("."))
0828: fileAbsPath = fileAbsPath + "/";
0829: String absPath = normalize(fileAbsPath);
0830: if (canPath != null)
0831: canPath = normalize(canPath);
0832: if ((absoluteBase.length() < absPath.length())
0833: && (absoluteBase.length() < canPath.length())) {
0834: absPath = absPath
0835: .substring(absoluteBase.length() + 1);
0836: if ((canPath == null) || (absPath == null))
0837: return null;
0838: if (absPath.equals(""))
0839: absPath = "/";
0840: canPath = canPath
0841: .substring(absoluteBase.length() + 1);
0842: if (canPath.equals(""))
0843: canPath = "/";
0844: if (!canPath.equals(absPath))
0845: return null;
0846: }
0847: }
0848:
0849: } else {
0850: return null;
0851: }
0852: return file;
0853:
0854: }
0855:
0856: /**
0857: * List the resources which are members of a collection.
0858: *
0859: * @param file Collection
0860: * @return Vector containg NamingEntry objects
0861: */
0862: protected Vector list(File file) {
0863:
0864: Vector entries = new Vector();
0865: if (!file.isDirectory())
0866: return entries;
0867: String[] names = file.list();
0868: Arrays.sort(names); // Sort alphabetically
0869: if (names == null)
0870: return entries;
0871: NamingEntry entry = null;
0872:
0873: for (int i = 0; i < names.length; i++) {
0874:
0875: File currentFile = new File(file, names[i]);
0876: Object object = null;
0877: if (currentFile.isDirectory()) {
0878: FileDirContext tempContext = new FileDirContext(env);
0879: tempContext.setDocBase(file.getPath());
0880: object = tempContext;
0881: } else {
0882: object = new FileResource(currentFile);
0883: }
0884: entry = new NamingEntry(names[i], object, NamingEntry.ENTRY);
0885: entries.addElement(entry);
0886:
0887: }
0888:
0889: return entries;
0890:
0891: }
0892:
0893: // ----------------------------------------------- FileResource Inner Class
0894:
0895: /**
0896: * This specialized resource implementation avoids opening the IputStream
0897: * to the file right away (which would put a lock on the file).
0898: */
0899: protected class FileResource extends Resource {
0900:
0901: // -------------------------------------------------------- Constructor
0902:
0903: public FileResource(File file) {
0904: this .file = file;
0905: }
0906:
0907: // --------------------------------------------------- Member Variables
0908:
0909: /**
0910: * Associated file object.
0911: */
0912: protected File file;
0913:
0914: /**
0915: * File length.
0916: */
0917: protected long length = -1L;
0918:
0919: // --------------------------------------------------- Resource Methods
0920:
0921: /**
0922: * Content accessor.
0923: *
0924: * @return InputStream
0925: */
0926: public InputStream streamContent() throws IOException {
0927: if (binaryContent == null) {
0928: inputStream = new FileInputStream(file);
0929: }
0930: return super .streamContent();
0931: }
0932:
0933: }
0934:
0935: // ------------------------------------- FileResourceAttributes Inner Class
0936:
0937: /**
0938: * This specialized resource attribute implementation does some lazy
0939: * reading (to speed up simple checks, like checking the last modified
0940: * date).
0941: */
0942: protected class FileResourceAttributes extends ResourceAttributes {
0943:
0944: // -------------------------------------------------------- Constructor
0945:
0946: public FileResourceAttributes(File file) {
0947: this .file = file;
0948: }
0949:
0950: // --------------------------------------------------- Member Variables
0951:
0952: protected File file;
0953:
0954: protected boolean accessed = false;
0955:
0956: // ----------------------------------------- ResourceAttributes Methods
0957:
0958: /**
0959: * Is collection.
0960: */
0961: public boolean isCollection() {
0962: if (!accessed) {
0963: collection = file.isDirectory();
0964: accessed = true;
0965: }
0966: return super .isCollection();
0967: }
0968:
0969: /**
0970: * Get content length.
0971: *
0972: * @return content length value
0973: */
0974: public long getContentLength() {
0975: if (contentLength != -1L)
0976: return contentLength;
0977: contentLength = file.length();
0978: return contentLength;
0979: }
0980:
0981: /**
0982: * Get creation time.
0983: *
0984: * @return creation time value
0985: */
0986: public long getCreation() {
0987: if (creation != -1L)
0988: return creation;
0989: creation = file.lastModified();
0990: return creation;
0991: }
0992:
0993: /**
0994: * Get creation date.
0995: *
0996: * @return Creation date value
0997: */
0998: public Date getCreationDate() {
0999: if (creation == -1L) {
1000: creation = file.lastModified();
1001: }
1002: return super .getCreationDate();
1003: }
1004:
1005: /**
1006: * Get last modified time.
1007: *
1008: * @return lastModified time value
1009: */
1010: public long getLastModified() {
1011: if (lastModified != -1L)
1012: return lastModified;
1013: lastModified = file.lastModified();
1014: return lastModified;
1015: }
1016:
1017: /**
1018: * Get lastModified date.
1019: *
1020: * @return LastModified date value
1021: */
1022: public Date getLastModifiedDate() {
1023: if (lastModified == -1L) {
1024: lastModified = file.lastModified();
1025: }
1026: return super .getLastModifiedDate();
1027: }
1028:
1029: /**
1030: * Get name.
1031: *
1032: * @return Name value
1033: */
1034: public String getName() {
1035: if (name == null)
1036: name = file.getName();
1037: return name;
1038: }
1039:
1040: /**
1041: * Get resource type.
1042: *
1043: * @return String resource type
1044: */
1045: public String getResourceType() {
1046: if (!accessed) {
1047: collection = file.isDirectory();
1048: accessed = true;
1049: }
1050: return super.getResourceType();
1051: }
1052:
1053: }
1054:
1055: }
|