Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » naming » resources » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   package org.apache.naming.resources;
   20   
   21   import java.io.File;
   22   import java.io.FileInputStream;
   23   import java.io.FileOutputStream;
   24   import java.io.IOException;
   25   import java.io.InputStream;
   26   import java.util.ArrayList;
   27   import java.util.Arrays;
   28   import java.util.Date;
   29   import java.util.Hashtable;
   30   
   31   import javax.naming.NameAlreadyBoundException;
   32   import javax.naming.NamingEnumeration;
   33   import javax.naming.NamingException;
   34   import javax.naming.OperationNotSupportedException;
   35   import javax.naming.directory.Attributes;
   36   import javax.naming.directory.DirContext;
   37   import javax.naming.directory.ModificationItem;
   38   import javax.naming.directory.SearchControls;
   39   
   40   import org.apache.naming.NamingContextBindingsEnumeration;
   41   import org.apache.naming.NamingContextEnumeration;
   42   import org.apache.naming.NamingEntry;
   43   
   44   /**
   45    * Filesystem Directory Context implementation helper class.
   46    *
   47    * @author Remy Maucherat
   48    * @version $Revision: 607568 $ $Date: 2007-12-30 18:56:50 +0100 (dim., 30 déc. 2007) $
   49    */
   50   
   51   public class FileDirContext extends BaseDirContext {
   52   
   53       private static org.apache.juli.logging.Log log=
   54           org.apache.juli.logging.LogFactory.getLog( FileDirContext.class );
   55   
   56       // -------------------------------------------------------------- Constants
   57   
   58   
   59       /**
   60        * The descriptive information string for this implementation.
   61        */
   62       protected static final int BUFFER_SIZE = 2048;
   63   
   64   
   65       // ----------------------------------------------------------- Constructors
   66   
   67   
   68       /**
   69        * Builds a file directory context using the given environment.
   70        */
   71       public FileDirContext() {
   72           super();
   73       }
   74   
   75   
   76       /**
   77        * Builds a file directory context using the given environment.
   78        */
   79       public FileDirContext(Hashtable env) {
   80           super(env);
   81       }
   82   
   83   
   84       // ----------------------------------------------------- Instance Variables
   85   
   86   
   87       /**
   88        * The document base directory.
   89        */
   90       protected File base = null;
   91   
   92   
   93       /**
   94        * Absolute normalized filename of the base.
   95        */
   96       protected String absoluteBase = null;
   97   
   98   
   99       /**
  100        * Case sensitivity.
  101        */
  102       protected boolean caseSensitive = true;
  103   
  104   
  105       /**
  106        * Allow linking.
  107        */
  108       protected boolean allowLinking = false;
  109   
  110   
  111       // ------------------------------------------------------------- Properties
  112   
  113   
  114       /**
  115        * Set the document root.
  116        *
  117        * @param docBase The new document root
  118        *
  119        * @exception IllegalArgumentException if the specified value is not
  120        *  supported by this implementation
  121        * @exception IllegalArgumentException if this would create a
  122        *  malformed URL
  123        */
  124       public void setDocBase(String docBase) {
  125   
  126       // Validate the format of the proposed document root
  127       if (docBase == null)
  128           throw new IllegalArgumentException
  129           (sm.getString("resources.null"));
  130   
  131       // Calculate a File object referencing this document base directory
  132       base = new File(docBase);
  133           try {
  134               base = base.getCanonicalFile();
  135           } catch (IOException e) {
  136               // Ignore
  137           }
  138   
  139       // Validate that the document base is an existing directory
  140       if (!base.exists() || !base.isDirectory() || !base.canRead())
  141           throw new IllegalArgumentException
  142           (sm.getString("fileResources.base", docBase));
  143           this.absoluteBase = base.getAbsolutePath();
  144           super.setDocBase(docBase);
  145   
  146       }
  147   
  148   
  149       /**
  150        * Set case sensitivity.
  151        */
  152       public void setCaseSensitive(boolean caseSensitive) {
  153           this.caseSensitive = caseSensitive;
  154       }
  155   
  156   
  157       /**
  158        * Is case sensitive ?
  159        */
  160       public boolean isCaseSensitive() {
  161           return caseSensitive;
  162       }
  163   
  164   
  165       /**
  166        * Set allow linking.
  167        */
  168       public void setAllowLinking(boolean allowLinking) {
  169           this.allowLinking = allowLinking;
  170       }
  171   
  172   
  173       /**
  174        * Is linking allowed.
  175        */
  176       public boolean getAllowLinking() {
  177           return allowLinking;
  178       }
  179   
  180   
  181       // --------------------------------------------------------- Public Methods
  182   
  183   
  184       /**
  185        * Release any resources allocated for this directory context.
  186        */
  187       public void release() {
  188           super.release();
  189       }
  190   
  191   
  192       // -------------------------------------------------------- Context Methods
  193   
  194   
  195       /**
  196        * Retrieves the named object.
  197        *
  198        * @param name the name of the object to look up
  199        * @return the object bound to name
  200        * @exception NamingException if a naming exception is encountered
  201        */
  202       public Object lookup(String name)
  203           throws NamingException {
  204           Object result = null;
  205           File file = file(name);
  206   
  207           if (file == null)
  208               throw new NamingException
  209                   (sm.getString("resources.notFound", name));
  210   
  211           if (file.isDirectory()) {
  212               FileDirContext tempContext = new FileDirContext(env);
  213               tempContext.setDocBase(file.getPath());
  214               tempContext.setAllowLinking(getAllowLinking());
  215               tempContext.setCaseSensitive(isCaseSensitive());
  216               result = tempContext;
  217           } else {
  218               result = new FileResource(file);
  219           }
  220   
  221           return result;
  222   
  223       }
  224   
  225   
  226       /**
  227        * Unbinds the named object. Removes the terminal atomic name in name
  228        * from the target context--that named by all but the terminal atomic
  229        * part of name.
  230        * <p>
  231        * This method is idempotent. It succeeds even if the terminal atomic
  232        * name is not bound in the target context, but throws
  233        * NameNotFoundException if any of the intermediate contexts do not exist.
  234        *
  235        * @param name the name to bind; may not be empty
  236        * @exception NameNotFoundException if an intermediate context does not
  237        * exist
  238        * @exception NamingException if a naming exception is encountered
  239        */
  240       public void unbind(String name)
  241           throws NamingException {
  242   
  243           File file = file(name);
  244   
  245           if (file == null)
  246               throw new NamingException
  247                   (sm.getString("resources.notFound", name));
  248   
  249           if (!file.delete())
  250               throw new NamingException
  251                   (sm.getString("resources.unbindFailed", name));
  252   
  253       }
  254   
  255   
  256       /**
  257        * Binds a new name to the object bound to an old name, and unbinds the
  258        * old name. Both names are relative to this context. Any attributes
  259        * associated with the old name become associated with the new name.
  260        * Intermediate contexts of the old name are not changed.
  261        *
  262        * @param oldName the name of the existing binding; may not be empty
  263        * @param newName the name of the new binding; may not be empty
  264        * @exception NameAlreadyBoundException if newName is already bound
  265        * @exception NamingException if a naming exception is encountered
  266        */
  267       public void rename(String oldName, String newName)
  268           throws NamingException {
  269   
  270           File file = file(oldName);
  271   
  272           if (file == null)
  273               throw new NamingException
  274                   (sm.getString("resources.notFound", oldName));
  275   
  276           File newFile = new File(base, newName);
  277   
  278           file.renameTo(newFile);
  279   
  280       }
  281   
  282   
  283       /**
  284        * Enumerates the names bound in the named context, along with the class
  285        * names of objects bound to them. The contents of any subcontexts are
  286        * not included.
  287        * <p>
  288        * If a binding is added to or removed from this context, its effect on
  289        * an enumeration previously returned is undefined.
  290        *
  291        * @param name the name of the context to list
  292        * @return an enumeration of the names and class names of the bindings in
  293        * this context. Each element of the enumeration is of type NameClassPair.
  294        * @exception NamingException if a naming exception is encountered
  295        */
  296       public NamingEnumeration list(String name)
  297           throws NamingException {
  298   
  299           File file = file(name);
  300   
  301           if (file == null)
  302               throw new NamingException
  303                   (sm.getString("resources.notFound", name));
  304   
  305           return new NamingContextEnumeration(list(file).iterator());
  306   
  307       }
  308   
  309   
  310       /**
  311        * Enumerates the names bound in the named context, along with the
  312        * objects bound to them. The contents of any subcontexts are not
  313        * included.
  314        * <p>
  315        * If a binding is added to or removed from this context, its effect on
  316        * an enumeration previously returned is undefined.
  317        *
  318        * @param name the name of the context to list
  319        * @return an enumeration of the bindings in this context.
  320        * Each element of the enumeration is of type Binding.
  321        * @exception NamingException if a naming exception is encountered
  322        */
  323       public NamingEnumeration listBindings(String name)
  324           throws NamingException {
  325   
  326           File file = file(name);
  327   
  328           if (file == null)
  329               throw new NamingException
  330                   (sm.getString("resources.notFound", name));
  331   
  332           return new NamingContextBindingsEnumeration(list(file).iterator(),
  333                   this);
  334   
  335       }
  336   
  337   
  338       /**
  339        * Destroys the named context and removes it from the namespace. Any
  340        * attributes associated with the name are also removed. Intermediate
  341        * contexts are not destroyed.
  342        * <p>
  343        * This method is idempotent. It succeeds even if the terminal atomic
  344        * name is not bound in the target context, but throws
  345        * NameNotFoundException if any of the intermediate contexts do not exist.
  346        *
  347        * In a federated naming system, a context from one naming system may be
  348        * bound to a name in another. One can subsequently look up and perform
  349        * operations on the foreign context using a composite name. However, an
  350        * attempt destroy the context using this composite name will fail with
  351        * NotContextException, because the foreign context is not a "subcontext"
  352        * of the context in which it is bound. Instead, use unbind() to remove
  353        * the binding of the foreign context. Destroying the foreign context
  354        * requires that the destroySubcontext() be performed on a context from
  355        * the foreign context's "native" naming system.
  356        *
  357        * @param name the name of the context to be destroyed; may not be empty
  358        * @exception NameNotFoundException if an intermediate context does not
  359        * exist
  360        * @exception NotContextException if the name is bound but does not name
  361        * a context, or does not name a context of the appropriate type
  362        */
  363       public void destroySubcontext(String name)
  364           throws NamingException {
  365           unbind(name);
  366       }
  367   
  368   
  369       /**
  370        * Retrieves the named object, following links except for the terminal
  371        * atomic component of the name. If the object bound to name is not a
  372        * link, returns the object itself.
  373        *
  374        * @param name the name of the object to look up
  375        * @return the object bound to name, not following the terminal link
  376        * (if any).
  377        * @exception NamingException if a naming exception is encountered
  378        */
  379       public Object lookupLink(String name)
  380           throws NamingException {
  381           // Note : Links are not supported
  382           return lookup(name);
  383       }
  384   
  385   
  386       /**
  387        * Retrieves the full name of this context within its own namespace.
  388        * <p>
  389        * Many naming services have a notion of a "full name" for objects in
  390        * their respective namespaces. For example, an LDAP entry has a
  391        * distinguished name, and a DNS record has a fully qualified name. This
  392        * method allows the client application to retrieve this name. The string
  393        * returned by this method is not a JNDI composite name and should not be
  394        * passed directly to context methods. In naming systems for which the
  395        * notion of full name does not make sense,
  396        * OperationNotSupportedException is thrown.
  397        *
  398        * @return this context's name in its own namespace; never null
  399        * @exception OperationNotSupportedException if the naming system does
  400        * not have the notion of a full name
  401        * @exception NamingException if a naming exception is encountered
  402        */
  403       public String getNameInNamespace()
  404           throws NamingException {
  405           return docBase;
  406       }
  407   
  408   
  409       // ----------------------------------------------------- DirContext Methods
  410   
  411   
  412       /**
  413        * Retrieves selected attributes associated with a named object.
  414        * See the class description regarding attribute models, attribute type
  415        * names, and operational attributes.
  416        *
  417        * @return the requested attributes; never null
  418        * @param name the name of the object from which to retrieve attributes
  419        * @param attrIds the identifiers of the attributes to retrieve. null
  420        * indicates that all attributes should be retrieved; an empty array
  421        * indicates that none should be retrieved
  422        * @exception NamingException if a naming exception is encountered
  423        */
  424       public Attributes getAttributes(String name, String[] attrIds)
  425           throws NamingException {
  426   
  427           // Building attribute list
  428           File file = file(name);
  429   
  430           if (file == null)
  431               throw new NamingException
  432                   (sm.getString("resources.notFound", name));
  433   
  434           return new FileResourceAttributes(file);
  435   
  436       }
  437   
  438   
  439       /**
  440        * Modifies the attributes associated with a named object. The order of
  441        * the modifications is not specified. Where possible, the modifications
  442        * are performed atomically.
  443        *
  444        * @param name the name of the object whose attributes will be updated
  445        * @param mod_op the modification operation, one of: ADD_ATTRIBUTE,
  446        * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
  447        * @param attrs the attributes to be used for the modification; may not
  448        * be null
  449        * @exception AttributeModificationException if the modification cannot be
  450        * completed successfully
  451        * @exception NamingException if a naming exception is encountered
  452        */
  453       public void modifyAttributes(String name, int mod_op, Attributes attrs)
  454           throws NamingException {
  455   
  456       }
  457   
  458   
  459       /**
  460        * Modifies the attributes associated with a named object using an an
  461        * ordered list of modifications. The modifications are performed in the
  462        * order specified. Each modification specifies a modification operation
  463        * code and an attribute on which to operate. Where possible, the
  464        * modifications are performed atomically.
  465        *
  466        * @param name the name of the object whose attributes will be updated
  467        * @param mods an ordered sequence of modifications to be performed; may
  468        * not be null
  469        * @exception AttributeModificationException if the modification cannot be
  470        * completed successfully
  471        * @exception NamingException if a naming exception is encountered
  472        */
  473       public void modifyAttributes(String name, ModificationItem[] mods)
  474           throws NamingException {
  475   
  476       }
  477   
  478   
  479       /**
  480        * Binds a name to an object, along with associated attributes. If attrs
  481        * is null, the resulting binding will have the attributes associated
  482        * with obj if obj is a DirContext, and no attributes otherwise. If attrs
  483        * is non-null, the resulting binding will have attrs as its attributes;
  484        * any attributes associated with obj are ignored.
  485        *
  486        * @param name the name to bind; may not be empty
  487        * @param obj the object to bind; possibly null
  488        * @param attrs the attributes to associate with the binding
  489        * @exception NameAlreadyBoundException if name is already bound
  490        * @exception InvalidAttributesException if some "mandatory" attributes
  491        * of the binding are not supplied
  492        * @exception NamingException if a naming exception is encountered
  493        */
  494       public void bind(String name, Object obj, Attributes attrs)
  495           throws NamingException {
  496   
  497           // Note: No custom attributes allowed
  498   
  499           File file = new File(base, name);
  500           if (file.exists())
  501               throw new NameAlreadyBoundException
  502                   (sm.getString("resources.alreadyBound", name));
  503   
  504           rebind(name, obj, attrs);
  505   
  506       }
  507   
  508   
  509       /**
  510        * Binds a name to an object, along with associated attributes,
  511        * overwriting any existing binding. If attrs is null and obj is a
  512        * DirContext, the attributes from obj are used. If attrs is null and obj
  513        * is not a DirContext, any existing attributes associated with the object
  514        * already bound in the directory remain unchanged. If attrs is non-null,
  515        * any existing attributes associated with the object already bound in
  516        * the directory are removed and attrs is associated with the named
  517        * object. If obj is a DirContext and attrs is non-null, the attributes
  518        * of obj are ignored.
  519        *
  520        * @param name the name to bind; may not be empty
  521        * @param obj the object to bind; possibly null
  522        * @param attrs the attributes to associate with the binding
  523        * @exception InvalidAttributesException if some "mandatory" attributes
  524        * of the binding are not supplied
  525        * @exception NamingException if a naming exception is encountered
  526        */
  527       public void rebind(String name, Object obj, Attributes attrs)
  528           throws NamingException {
  529   
  530           // Note: No custom attributes allowed
  531           // Check obj type
  532   
  533           File file = new File(base, name);
  534   
  535           InputStream is = null;
  536           if (obj instanceof Resource) {
  537               try {
  538                   is = ((Resource) obj).streamContent();
  539               } catch (IOException e) {
  540               }
  541           } else if (obj instanceof InputStream) {
  542               is = (InputStream) obj;
  543           } else if (obj instanceof DirContext) {
  544               if (file.exists()) {
  545                   if (!file.delete())
  546                       throw new NamingException
  547                           (sm.getString("resources.bindFailed", name));
  548               }
  549               if (!file.mkdir())
  550                   throw new NamingException
  551                       (sm.getString("resources.bindFailed", name));
  552           }
  553           if (is == null)
  554               throw new NamingException
  555                   (sm.getString("resources.bindFailed", name));
  556   
  557           // Open os
  558   
  559           try {
  560               FileOutputStream os = null;
  561               byte buffer[] = new byte[BUFFER_SIZE];
  562               int len = -1;
  563               try {
  564                   os = new FileOutputStream(file);
  565                   while (true) {
  566                       len = is.read(buffer);
  567                       if (len == -1)
  568                           break;
  569                       os.write(buffer, 0, len);
  570                   }
  571               } finally {
  572                   if (os != null)
  573                       os.close();
  574                   is.close();
  575               }
  576           } catch (IOException e) {
  577               throw new NamingException
  578                   (sm.getString("resources.bindFailed", e));
  579           }
  580   
  581       }
  582   
  583   
  584       /**
  585        * Creates and binds a new context, along with associated attributes.
  586        * This method creates a new subcontext with the given name, binds it in
  587        * the target context (that named by all but terminal atomic component of
  588        * the name), and associates the supplied attributes with the newly
  589        * created object. All intermediate and target contexts must already
  590        * exist. If attrs is null, this method is equivalent to
  591        * Context.createSubcontext().
  592        *
  593        * @param name the name of the context to create; may not be empty
  594        * @param attrs the attributes to associate with the newly created context
  595        * @return the newly created context
  596        * @exception NameAlreadyBoundException if the name is already bound
  597        * @exception InvalidAttributesException if attrs does not contain all
  598        * the mandatory attributes required for creation
  599        * @exception NamingException if a naming exception is encountered
  600        */
  601       public DirContext createSubcontext(String name, Attributes attrs)
  602           throws NamingException {
  603   
  604           File file = new File(base, name);
  605           if (file.exists())
  606               throw new NameAlreadyBoundException
  607                   (sm.getString("resources.alreadyBound", name));
  608           if (!file.mkdir())
  609               throw new NamingException
  610                   (sm.getString("resources.bindFailed", name));
  611           return (DirContext) lookup(name);
  612   
  613       }
  614   
  615   
  616       /**
  617        * Retrieves the schema associated with the named object. The schema
  618        * describes rules regarding the structure of the namespace and the
  619        * attributes stored within it. The schema specifies what types of
  620        * objects can be added to the directory and where they can be added;
  621        * what mandatory and optional attributes an object can have. The range
  622        * of support for schemas is directory-specific.
  623        *
  624        * @param name the name of the object whose schema is to be retrieved
  625        * @return the schema associated with the context; never null
  626        * @exception OperationNotSupportedException if schema not supported
  627        * @exception NamingException if a naming exception is encountered
  628        */
  629       public DirContext getSchema(String name)
  630           throws NamingException {
  631           throw new OperationNotSupportedException();
  632       }
  633   
  634   
  635       /**
  636        * Retrieves a context containing the schema objects of the named
  637        * object's class definitions.
  638        *
  639        * @param name the name of the object whose object class definition is to
  640        * be retrieved
  641        * @return the DirContext containing the named object's class
  642        * definitions; never null
  643        * @exception OperationNotSupportedException if schema not supported
  644        * @exception NamingException if a naming exception is encountered
  645        */
  646       public DirContext getSchemaClassDefinition(String name)
  647           throws NamingException {
  648           throw new OperationNotSupportedException();
  649       }
  650   
  651   
  652       /**
  653        * Searches in a single context for objects that contain a specified set
  654        * of attributes, and retrieves selected attributes. The search is
  655        * performed using the default SearchControls settings.
  656        *
  657        * @param name the name of the context to search
  658        * @param matchingAttributes the attributes to search for. If empty or
  659        * null, all objects in the target context are returned.
  660        * @param attributesToReturn the attributes to return. null indicates
  661        * that all attributes are to be returned; an empty array indicates that
  662        * none are to be returned.
  663        * @return a non-null enumeration of SearchResult objects. Each
  664        * SearchResult contains the attributes identified by attributesToReturn
  665        * and the name of the corresponding object, named relative to the
  666        * context named by name.
  667        * @exception NamingException if a naming exception is encountered
  668        */
  669       public NamingEnumeration search(String name, Attributes matchingAttributes,
  670                                       String[] attributesToReturn)
  671           throws NamingException {
  672           return null;
  673       }
  674   
  675   
  676       /**
  677        * Searches in a single context for objects that contain a specified set
  678        * of attributes. This method returns all the attributes of such objects.
  679        * It is equivalent to supplying null as the atributesToReturn parameter
  680        * to the method search(Name, Attributes, String[]).
  681        *
  682        * @param name the name of the context to search
  683        * @param matchingAttributes the attributes to search for. If empty or
  684        * null, all objects in the target context are returned.
  685        * @return a non-null enumeration of SearchResult objects. Each
  686        * SearchResult contains the attributes identified by attributesToReturn
  687        * and the name of the corresponding object, named relative to the
  688        * context named by name.
  689        * @exception NamingException if a naming exception is encountered
  690        */
  691       public NamingEnumeration search(String name, Attributes matchingAttributes)
  692           throws NamingException {
  693           return null;
  694       }
  695   
  696   
  697       /**
  698        * Searches in the named context or object for entries that satisfy the
  699        * given search filter. Performs the search as specified by the search
  700        * controls.
  701        *
  702        * @param name the name of the context or object to search
  703        * @param filter the filter expression to use for the search; may not be
  704        * null
  705        * @param cons the search controls that control the search. If null,
  706        * the default search controls are used (equivalent to
  707        * (new SearchControls())).
  708        * @return an enumeration of SearchResults of the objects that satisfy
  709        * the filter; never null
  710        * @exception InvalidSearchFilterException if the search filter specified
  711        * is not supported or understood by the underlying directory
  712        * @exception InvalidSearchControlsException if the search controls
  713        * contain invalid settings
  714        * @exception NamingException if a naming exception is encountered
  715        */
  716       public NamingEnumeration search(String name, String filter,
  717                                       SearchControls cons)
  718           throws NamingException {
  719           return null;
  720       }
  721   
  722   
  723       /**
  724        * Searches in the named context or object for entries that satisfy the
  725        * given search filter. Performs the search as specified by the search
  726        * controls.
  727        *
  728        * @param name the name of the context or object to search
  729        * @param filterExpr the filter expression to use for the search.
  730        * The expression may contain variables of the form "{i}" where i is a
  731        * nonnegative integer. May not be null.
  732        * @param filterArgs the array of arguments to substitute for the
  733        * variables in filterExpr. The value of filterArgs[i] will replace each
  734        * occurrence of "{i}". If null, equivalent to an empty array.
  735        * @param cons the search controls that control the search. If null, the
  736        * default search controls are used (equivalent to (new SearchControls())).
  737        * @return an enumeration of SearchResults of the objects that satisy the
  738        * filter; never null
  739        * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i}
  740        * expressions where i is outside the bounds of the array filterArgs
  741        * @exception InvalidSearchControlsException if cons contains invalid
  742        * settings
  743        * @exception InvalidSearchFilterException if filterExpr with filterArgs
  744        * represents an invalid search filter
  745        * @exception NamingException if a naming exception is encountered
  746        */
  747       public NamingEnumeration search(String name, String filterExpr,
  748                                       Object[] filterArgs, SearchControls cons)
  749           throws NamingException {
  750           return null;
  751       }
  752   
  753   
  754       // ------------------------------------------------------ Protected Methods
  755   
  756   
  757       /**
  758        * Return a context-relative path, beginning with a "/", that represents
  759        * the canonical version of the specified path after ".." and "." elements
  760        * are resolved out.  If the specified path attempts to go outside the
  761        * boundaries of the current context (i.e. too many ".." path elements
  762        * are present), return <code>null</code> instead.
  763        *
  764        * @param path Path to be normalized
  765        */
  766       protected String normalize(String path) {
  767   
  768       String normalized = path;
  769   
  770       // Normalize the slashes and add leading slash if necessary
  771       if (File.separatorChar == '\\' && normalized.indexOf('\\') >= 0)
  772           normalized = normalized.replace('\\', '/');
  773       if (!normalized.startsWith("/"))
  774           normalized = "/" + normalized;
  775   
  776       // Resolve occurrences of "//" in the normalized path
  777       while (true) {
  778           int index = normalized.indexOf("//");
  779           if (index < 0)
  780           break;
  781           normalized = normalized.substring(0, index) +
  782           normalized.substring(index + 1);
  783       }
  784   
  785       // Resolve occurrences of "/./" in the normalized path
  786       while (true) {
  787           int index = normalized.indexOf("/./");
  788           if (index < 0)
  789           break;
  790           normalized = normalized.substring(0, index) +
  791           normalized.substring(index + 2);
  792       }
  793   
  794       // Resolve occurrences of "/../" in the normalized path
  795       while (true) {
  796           int index = normalized.indexOf("/../");
  797           if (index < 0)
  798           break;
  799           if (index == 0)
  800           return (null);  // Trying to go outside our context
  801           int index2 = normalized.lastIndexOf('/', index - 1);
  802           normalized = normalized.substring(0, index2) +
  803           normalized.substring(index + 3);
  804       }
  805   
  806       // Return the normalized path that we have completed
  807       return (normalized);
  808   
  809       }
  810   
  811   
  812       /**
  813        * Return a File object representing the specified normalized
  814        * context-relative path if it exists and is readable.  Otherwise,
  815        * return <code>null</code>.
  816        *
  817        * @param name Normalized context-relative path (with leading '/')
  818        */
  819       protected File file(String name) {
  820   
  821           File file = new File(base, name);
  822           if (file.exists() && file.canRead()) {
  823   
  824           	if (allowLinking)
  825           		return file;
  826           	
  827               // Check that this file belongs to our root path
  828               String canPath = null;
  829               try {
  830                   canPath = file.getCanonicalPath();
  831               } catch (IOException e) {
  832               }
  833               if (canPath == null)
  834                   return null;
  835   
  836               // Check to see if going outside of the web application root
  837               if (!canPath.startsWith(absoluteBase)) {
  838                   return null;
  839               }
  840   
  841               // Case sensitivity check
  842               if (caseSensitive) {
  843                   String fileAbsPath = file.getAbsolutePath();
  844                   if (fileAbsPath.endsWith("."))
  845                       fileAbsPath = fileAbsPath + "/";
  846                   String absPath = normalize(fileAbsPath);
  847                   if (canPath != null)
  848                       canPath = normalize(canPath);
  849                   if ((absoluteBase.length() < absPath.length())
  850                       && (absoluteBase.length() < canPath.length())) {
  851                       absPath = absPath.substring(absoluteBase.length() + 1);
  852                       if ((canPath == null) || (absPath == null))
  853                           return null;
  854                       if (absPath.equals(""))
  855                           absPath = "/";
  856                       canPath = canPath.substring(absoluteBase.length() + 1);
  857                       if (canPath.equals(""))
  858                           canPath = "/";
  859                       if (!canPath.equals(absPath))
  860                           return null;
  861                   }
  862               }
  863   
  864           } else {
  865               return null;
  866           }
  867           return file;
  868   
  869       }
  870   
  871   
  872       /**
  873        * List the resources which are members of a collection.
  874        *
  875        * @param file Collection
  876        * @return Vector containg NamingEntry objects
  877        */
  878       protected ArrayList list(File file) {
  879   
  880           ArrayList entries = new ArrayList();
  881           if (!file.isDirectory())
  882               return entries;
  883           String[] names = file.list();
  884           if (names==null) {
  885               /* Some IO error occurred such as bad file permissions.
  886                  Prevent a NPE with Arrays.sort(names) */
  887               log.warn(sm.getString("fileResources.listingNull",
  888                                     file.getAbsolutePath()));
  889               return entries;
  890           }
  891   
  892           Arrays.sort(names);             // Sort alphabetically
  893           if (names == null)
  894               return entries;
  895           NamingEntry entry = null;
  896   
  897           for (int i = 0; i < names.length; i++) {
  898   
  899               File currentFile = new File(file, names[i]);
  900               Object object = null;
  901               if (currentFile.isDirectory()) {
  902                   FileDirContext tempContext = new FileDirContext(env);
  903                   tempContext.setDocBase(file.getPath());
  904                   tempContext.setAllowLinking(getAllowLinking());
  905                   tempContext.setCaseSensitive(isCaseSensitive());
  906                   object = tempContext;
  907               } else {
  908                   object = new FileResource(currentFile);
  909               }
  910               entry = new NamingEntry(names[i], object, NamingEntry.ENTRY);
  911               entries.add(entry);
  912   
  913           }
  914   
  915           return entries;
  916   
  917       }
  918   
  919   
  920       // ----------------------------------------------- FileResource Inner Class
  921   
  922   
  923       /**
  924        * This specialized resource implementation avoids opening the IputStream
  925        * to the file right away (which would put a lock on the file).
  926        */
  927       protected class FileResource extends Resource {
  928   
  929   
  930           // -------------------------------------------------------- Constructor
  931   
  932   
  933           public FileResource(File file) {
  934               this.file = file;
  935           }
  936   
  937   
  938           // --------------------------------------------------- Member Variables
  939   
  940   
  941           /**
  942            * Associated file object.
  943            */
  944           protected File file;
  945   
  946   
  947           /**
  948            * File length.
  949            */
  950           protected long length = -1L;
  951   
  952   
  953           // --------------------------------------------------- Resource Methods
  954   
  955   
  956           /**
  957            * Content accessor.
  958            *
  959            * @return InputStream
  960            */
  961           public InputStream streamContent()
  962               throws IOException {
  963               if (binaryContent == null) {
  964                   inputStream = new FileInputStream(file);
  965               }
  966               return super.streamContent();
  967           }
  968   
  969   
  970       }
  971   
  972   
  973       // ------------------------------------- FileResourceAttributes Inner Class
  974   
  975   
  976       /**
  977        * This specialized resource attribute implementation does some lazy
  978        * reading (to speed up simple checks, like checking the last modified
  979        * date).
  980        */
  981       protected class FileResourceAttributes extends ResourceAttributes {
  982   
  983   
  984           // -------------------------------------------------------- Constructor
  985   
  986   
  987           public FileResourceAttributes(File file) {
  988               this.file = file;
  989               getCreation();
  990               getLastModified();
  991           }
  992   
  993           // --------------------------------------------------- Member Variables
  994   
  995   
  996           protected File file;
  997   
  998   
  999           protected boolean accessed = false;
 1000   
 1001   
 1002           protected String canonicalPath = null;
 1003   
 1004   
 1005           // ----------------------------------------- ResourceAttributes Methods
 1006   
 1007   
 1008           /**
 1009            * Is collection.
 1010            */
 1011           public boolean isCollection() {
 1012               if (!accessed) {
 1013                   collection = file.isDirectory();
 1014                   accessed = true;
 1015               }
 1016               return super.isCollection();
 1017           }
 1018   
 1019   
 1020           /**
 1021            * Get content length.
 1022            *
 1023            * @return content length value
 1024            */
 1025           public long getContentLength() {
 1026               if (contentLength != -1L)
 1027                   return contentLength;
 1028               contentLength = file.length();
 1029               return contentLength;
 1030           }
 1031   
 1032   
 1033           /**
 1034            * Get creation time.
 1035            *
 1036            * @return creation time value
 1037            */
 1038           public long getCreation() {
 1039               if (creation != -1L)
 1040                   return creation;
 1041               creation = getLastModified();
 1042               return creation;
 1043           }
 1044   
 1045   
 1046           /**
 1047            * Get creation date.
 1048            *
 1049            * @return Creation date value
 1050            */
 1051           public Date getCreationDate() {
 1052               if (creation == -1L) {
 1053                   creation = getCreation();
 1054               }
 1055               return super.getCreationDate();
 1056           }
 1057   
 1058   
 1059           /**
 1060            * Get last modified time.
 1061            *
 1062            * @return lastModified time value
 1063            */
 1064           public long getLastModified() {
 1065               if (lastModified != -1L)
 1066                   return lastModified;
 1067               lastModified = file.lastModified();
 1068               return lastModified;
 1069           }
 1070   
 1071   
 1072           /**
 1073            * Get lastModified date.
 1074            *
 1075            * @return LastModified date value
 1076            */
 1077           public Date getLastModifiedDate() {
 1078               if (lastModified == -1L) {
 1079                   lastModified = getLastModified();
 1080               }
 1081               return super.getLastModifiedDate();
 1082           }
 1083   
 1084   
 1085           /**
 1086            * Get name.
 1087            *
 1088            * @return Name value
 1089            */
 1090           public String getName() {
 1091               if (name == null)
 1092                   name = file.getName();
 1093               return name;
 1094           }
 1095   
 1096   
 1097           /**
 1098            * Get resource type.
 1099            *
 1100            * @return String resource type
 1101            */
 1102           public String getResourceType() {
 1103               if (!accessed) {
 1104                   collection = file.isDirectory();
 1105                   accessed = true;
 1106               }
 1107               return super.getResourceType();
 1108           }
 1109   
 1110           
 1111           /**
 1112            * Get canonical path.
 1113            * 
 1114            * @return String the file's canonical path
 1115            */
 1116           public String getCanonicalPath() {
 1117               if (canonicalPath == null) {
 1118                   try {
 1119                       canonicalPath = file.getCanonicalPath();
 1120                   } catch (IOException e) {
 1121                       // Ignore
 1122                   }
 1123               }
 1124               return canonicalPath;
 1125           }
 1126           
 1127   
 1128       }
 1129   
 1130   
 1131   }
 1132   

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » naming » resources » [javadoc | source]