/**
   * Destroys the named context and removes it from the namespace. Any attributes associated with
   * the name are also removed. Intermediate contexts are not destroyed.
   *
   * <p>This method is idempotent. It succeeds even if the terminal atomic name is not bound in the
   * target context, but throws NameNotFoundException if any of the intermediate contexts do not
   * exist.
   *
   * <p>In a federated naming system, a context from one naming system may be bound to a name in
   * another. One can subsequently look up and perform operations on the foreign context using a
   * composite name. However, an attempt destroy the context using this composite name will fail
   * with NotContextException, because the foreign context is not a "subcontext" of the context in
   * which it is bound. Instead, use unbind() to remove the binding of the foreign context.
   * Destroying the foreign context requires that the destroySubcontext() be performed on a context
   * from the foreign context's "native" naming system.
   *
   * @param name the name of the context to be destroyed; may not be empty
   * @exception NameNotFoundException if an intermediate context does not exist
   * @exception NotContextException if the name is bound but does not name a context, or does not
   *     name a context of the appropriate type
   */
  @Override
  public void destroySubcontext(Name name) throws NamingException {

    if (!checkWritable()) {
      return;
    }

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) throw new NamingException(sm.getString("namingContext.invalidName"));

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (name.size() > 1) {
      if (entry.type == NamingEntry.CONTEXT) {
        ((Context) entry.value).destroySubcontext(name.getSuffix(1));
      } else {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
    } else {
      if (entry.type == NamingEntry.CONTEXT) {
        ((Context) entry.value).close();
        bindings.remove(name.get(0));
      } else {
        throw new NotContextException(sm.getString("namingContext.contextExpected"));
      }
    }
  }
  /**
   * Retrieves the named object.
   *
   * @param name the name of the object to look up
   * @param resolveLinks If true, the links will be resolved
   * @return the object bound to name
   * @exception NamingException if a naming exception is encountered
   */
  protected Object lookup(Name name, boolean resolveLinks) throws NamingException {

    // Removing empty parts
    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) {
      // If name is empty, a newly allocated naming context is returned
      return new NamingContext(env, this.name, bindings);
    }

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (name.size() > 1) {
      // If the size of the name is greater that 1, then we go through a
      // number of subcontexts.
      if (entry.type != NamingEntry.CONTEXT) {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
      return ((Context) entry.value).lookup(name.getSuffix(1));
    } else {
      if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) {
        String link = ((LinkRef) entry.value).getLinkName();
        if (link.startsWith(".")) {
          // Link relative to this context
          return lookup(link.substring(1));
        } else {
          return (new InitialContext(env)).lookup(link);
        }
      } else if (entry.type == NamingEntry.REFERENCE) {
        try {
          // TODO ÐèѧϰNamingManager
          Object obj = NamingManager.getObjectInstance(entry.value, name, this, env);
          if (entry.value instanceof ResourceRef) {
            boolean singleton =
                Boolean.parseBoolean(
                    (String) ((ResourceRef) entry.value).get("singleton").getContent());
            if (singleton) {
              entry.type = NamingEntry.ENTRY;
              entry.value = obj;
            }
          }
          return obj;
        } catch (NamingException e) {
          throw e;
        } catch (Exception e) {
          log.warn(sm.getString("namingContext.failResolvingReference"), e);
          throw new NamingException(e.getMessage());
        }
      } else {
        return entry.value;
      }
    }
  }
  /**
   * Binds a name to an object. All intermediate contexts and the target context (that named by all
   * but terminal atomic component of the name) must already exist.
   *
   * @param name the name to bind; may not be empty
   * @param obj the object to bind; possibly null
   * @param rebind if true, then perform a rebind (ie, overwrite)
   * @exception NameAlreadyBoundException if name is already bound
   * @exception javax.naming.directory.InvalidAttributesException if object did not supply all
   *     mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  protected void bind(Name name, Object obj, boolean rebind) throws NamingException {

    if (!checkWritable()) {
      return;
    }

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) throw new NamingException(sm.getString("namingContext.invalidName"));

    NamingEntry entry = bindings.get(name.get(0));

    if (name.size() > 1) {
      if (entry == null) {
        throw new NameNotFoundException(
            sm.getString("namingContext.nameNotBound", name, name.get(0)));
      }
      if (entry.type == NamingEntry.CONTEXT) {
        if (rebind) {
          ((Context) entry.value).rebind(name.getSuffix(1), obj);
        } else {
          ((Context) entry.value).bind(name.getSuffix(1), obj);
        }
      } else {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
    } else {
      if ((!rebind) && (entry != null)) {
        throw new NameAlreadyBoundException(
            sm.getString("namingContext.alreadyBound", name.get(0)));
      } else {
        // Getting the type of the object and wrapping it within a new
        // NamingEntry
        Object toBind = NamingManager.getStateToBind(obj, name, this, env);
        if (toBind instanceof Context) {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.CONTEXT);
        } else if (toBind instanceof LinkRef) {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.LINK_REF);
        } else if (toBind instanceof Reference) {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.REFERENCE);
        } else if (toBind instanceof Referenceable) {
          toBind = ((Referenceable) toBind).getReference();
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.REFERENCE);
        } else {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.ENTRY);
        }
        bindings.put(name.get(0), entry);
      }
    }
  }
Example #4
0
  public Message readMessage(int offset) {

    Message r = new Message();

    int t = readShort(offset + 8);
    r.end = (t == 0) ? null : strings.get(t);

    t = readShort(offset + 6);
    r.start = (t == 0) ? null : strings.get(t);

    r.brief = strings.get(readShort(offset + 12));
    r.full = strings.get(readShort(offset + 14));

    return r;
  }
Example #5
0
 public String ld() {
   try {
     return strings.get(readShort(attributesEnd + 0xc) + id().length() + 1);
   } catch (Exception e) {
     return "hw1";
   }
 }
Example #6
0
  private String[] readAttributeList(int offset) {
    int pos = offset + attributesStart;

    int cnt = readShort(pos);
    String[] tab = new String[cnt];

    int p = pos + 2;
    for (int i = 0; i < cnt; i++, p += 2) tab[i] = strings.get(readShort(p));

    return tab;
  }
 /** Throws a naming exception is Context is not writable. */
 protected boolean checkWritable() throws NamingException {
   if (isWritable()) {
     return true;
   } else {
     if (exceptionOnFailedWrite) {
       throw new javax.naming.OperationNotSupportedException(
           sm.getString("namingContext.readOnly"));
     }
   }
   return false;
 }
  /**
   * Enumerates the names bound in the named context, along with the objects bound to them. The
   * contents of any subcontexts are not included.
   *
   * <p>If a binding is added to or removed from this context, its effect on an enumeration
   * previously returned is undefined.
   *
   * @param name the name of the context to list
   * @return an enumeration of the bindings in this context. Each element of the enumeration is of
   *     type Binding.
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
    // Removing empty parts
    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) {
      return new NamingContextBindingsEnumeration(bindings.values().iterator(), this);
    }

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (entry.type != NamingEntry.CONTEXT) {
      throw new NamingException(sm.getString("namingContext.contextExpected"));
    }
    return ((Context) entry.value).listBindings(name.getSuffix(1));
  }
Example #9
0
  private void readStations() {

    stations = new Station[(attributesStart - stationsStart) / StationSize];

    for (int i = 0, pos = stationsStart; pos < attributesStart; pos += StationSize, i++) {
      stations[i] = new Station();
      stations[i].name = strings.get(readShort(pos));
      stations[i].id = readLong(pos + 2);
      stations[i].x = readLong(pos + 6);
      stations[i].y = readLong(pos + 10);
    }
  }
Example #10
0
  private Station readHeaderStation(int offset) {
    int nameLoc = readShort(offset);
    if (nameLoc == 0) return null;

    Station ret = new Station();

    ret.name = strings.get(nameLoc);
    ret.x = readLong(offset + 6);
    ret.y = readLong(offset + 10);

    return ret;
  }
Example #11
0
  Train readTrain(int pos) {
    Train r = new Train();

    r.offset = pos;
    r.deptime = new PLNTimestamp(readShort(pos));
    r.depstation = stations[readShort(pos + 2)];
    r.arrtime = new PLNTimestamp(readShort(pos + 4));
    r.arrstation = stations[readShort(pos + 6)];
    r.number = strings.get(readShort(pos + 10));

    r.attributesOffset = readShort(pos + 18);

    return r;
  }
  /**
   * Retrieves the parser associated with the named context. In a federation of namespaces,
   * different naming systems will parse names differently. This method allows an application to get
   * a parser for parsing names into their atomic components using the naming convention of a
   * particular naming system. Within any single naming system, NameParser objects returned by this
   * method must be equal (using the equals() test).
   *
   * @param name the name of the context from which to get the parser
   * @return a name parser that can parse compound names into their atomic components
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NameParser getNameParser(Name name) throws NamingException {

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) return nameParser;

    if (name.size() > 1) {
      Object obj = bindings.get(name.get(0));
      if (obj instanceof Context) {
        return ((Context) obj).getNameParser(name.getSuffix(1));
      } else {
        throw new NotContextException(sm.getString("namingContext.contextExpected"));
      }
    }

    return nameParser;
  }
Example #13
0
  private TrainChange readTrainChanges(int offset) {

    int rd = readShort(offset);
    int ra = readShort(offset + 2);
    int rdp = readShort(offset + 4);
    int rap = readShort(offset + 6);

    if (ra == 0xffff && rd == 0xffff && rdp == 0 && rap == 0) return null;

    delayInfo = true;

    TrainChange tc = new TrainChange();
    tc.realdeptime = (rd == 0xffff) ? null : new PLNTimestamp(rd);
    tc.realarrtime = (ra == 0xffff) ? null : new PLNTimestamp(ra);
    tc.realdepplatform = (rdp == 0) ? null : strings.get(rdp);
    tc.realarrplatform = (rap == 0) ? null : strings.get(rap);

    return tc;
  }
 /**
  * Retrieves the full name of this context within its own namespace.
  *
  * <p>Many naming services have a notion of a "full name" for objects in their respective
  * namespaces. For example, an LDAP entry has a distinguished name, and a DNS record has a fully
  * qualified name. This method allows the client application to retrieve this name. The string
  * returned by this method is not a JNDI composite name and should not be passed directly to
  * context methods. In naming systems for which the notion of full name does not make sense,
  * OperationNotSupportedException is thrown.
  *
  * @return this context's name in its own namespace; never null
  * @exception OperationNotSupportedException if the naming system does not have the notion of a
  *     full name
  * @exception NamingException if a naming exception is encountered
  */
 @Override
 public String getNameInNamespace() throws NamingException {
   throw new OperationNotSupportedException(sm.getString("namingContext.noAbsoluteName"));
   // FIXME ?
 }
/**
 * Catalina JNDI Context implementation.
 *
 * @author Remy Maucherat
 * @version $Id: NamingContext.java 1298123 2012-03-07 21:13:08Z markt $
 */
public class NamingContext implements Context {

  // -------------------------------------------------------------- Constants

  /** Name parser for this context. */
  protected static final NameParser nameParser = new NameParserImpl();

  private static final org.apache.juli.logging.Log log =
      org.apache.juli.logging.LogFactory.getLog(NamingContext.class);

  // ----------------------------------------------------------- Constructors

  /** Builds a naming context using the given environment. */
  public NamingContext(Hashtable<String, Object> env, String name) throws NamingException {
    this.bindings = new HashMap<String, NamingEntry>();
    this.env = new Hashtable<String, Object>();
    // FIXME ? Could be put in the environment ?
    this.name = name;
    // Populating the environment hashtable
    if (env != null) {
      Enumeration<String> envEntries = env.keys();
      while (envEntries.hasMoreElements()) {
        String entryName = envEntries.nextElement();
        addToEnvironment(entryName, env.get(entryName));
      }
    }
  }

  /** Builds a naming context using the given environment. */
  public NamingContext(
      Hashtable<String, Object> env, String name, HashMap<String, NamingEntry> bindings)
      throws NamingException {
    this(env, name);
    this.bindings = bindings;
  }

  // ----------------------------------------------------- Instance Variables

  /** Environment. */
  protected Hashtable<String, Object> env;

  /** The string manager for this package. */
  protected static final StringManager sm = StringManager.getManager(Constants.Package);

  /** Bindings in this Context. */
  protected HashMap<String, NamingEntry> bindings;

  /** Name of the associated Catalina Context. */
  protected String name;

  /**
   * Determines if an attempt to write to a read-only context results in an exception or if the
   * request is ignored.
   */
  private boolean exceptionOnFailedWrite = true;

  public boolean getExceptionOnFailedWrite() {
    return exceptionOnFailedWrite;
  }

  public void setExceptionOnFailedWrite(boolean exceptionOnFailedWrite) {
    this.exceptionOnFailedWrite = exceptionOnFailedWrite;
  }

  // -------------------------------------------------------- Context Methods

  /**
   * Retrieves the named object. If name is empty, returns a new instance of this context (which
   * represents the same naming context as this context, but its environment may be modified
   * independently and it may be accessed concurrently).
   *
   * @param name the name of the object to look up
   * @return the object bound to name
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Object lookup(Name name) throws NamingException {
    return lookup(name, true);
  }

  /**
   * Retrieves the named object.
   *
   * @param name the name of the object to look up
   * @return the object bound to name
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Object lookup(String name) throws NamingException {
    return lookup(new CompositeName(name), true);
  }

  /**
   * Binds a name to an object. All intermediate contexts and the target context (that named by all
   * but terminal atomic component of the name) must already exist.
   *
   * @param name the name to bind; may not be empty
   * @param obj the object to bind; possibly null
   * @exception NameAlreadyBoundException if name is already bound
   * @exception javax.naming.directory.InvalidAttributesException if object did not supply all
   *     mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void bind(Name name, Object obj) throws NamingException {
    bind(name, obj, false);
  }

  /**
   * Binds a name to an object.
   *
   * @param name the name to bind; may not be empty
   * @param obj the object to bind; possibly null
   * @exception NameAlreadyBoundException if name is already bound
   * @exception javax.naming.directory.InvalidAttributesException if object did not supply all
   *     mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void bind(String name, Object obj) throws NamingException {
    bind(new CompositeName(name), obj);
  }

  /**
   * Binds a name to an object, overwriting any existing binding. All intermediate contexts and the
   * target context (that named by all but terminal atomic component of the name) must already
   * exist.
   *
   * <p>If the object is a DirContext, any existing attributes associated with the name are replaced
   * with those of the object. Otherwise, any existing attributes associated with the name remain
   * unchanged.
   *
   * @param name the name to bind; may not be empty
   * @param obj the object to bind; possibly null
   * @exception javax.naming.directory.InvalidAttributesException if object did not supply all
   *     mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void rebind(Name name, Object obj) throws NamingException {
    bind(name, obj, true);
  }

  /**
   * Binds a name to an object, overwriting any existing binding.
   *
   * @param name the name to bind; may not be empty
   * @param obj the object to bind; possibly null
   * @exception javax.naming.directory.InvalidAttributesException if object did not supply all
   *     mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void rebind(String name, Object obj) throws NamingException {
    rebind(new CompositeName(name), obj);
  }

  /**
   * Unbinds the named object. Removes the terminal atomic name in name from the target
   * context--that named by all but the terminal atomic part of name.
   *
   * <p>This method is idempotent. It succeeds even if the terminal atomic name is not bound in the
   * target context, but throws NameNotFoundException if any of the intermediate contexts do not
   * exist.
   *
   * @param name the name to bind; may not be empty
   * @exception NameNotFoundException if an intermediate context does not exist
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void unbind(Name name) throws NamingException {

    if (!checkWritable()) {
      return;
    }

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) throw new NamingException(sm.getString("namingContext.invalidName"));

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (name.size() > 1) {
      if (entry.type == NamingEntry.CONTEXT) {
        ((Context) entry.value).unbind(name.getSuffix(1));
      } else {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
    } else {
      bindings.remove(name.get(0));
    }
  }

  /**
   * Unbinds the named object.
   *
   * @param name the name to bind; may not be empty
   * @exception NameNotFoundException if an intermediate context does not exist
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void unbind(String name) throws NamingException {
    unbind(new CompositeName(name));
  }

  /**
   * Binds a new name to the object bound to an old name, and unbinds the old name. Both names are
   * relative to this context. Any attributes associated with the old name become associated with
   * the new name. Intermediate contexts of the old name are not changed.
   *
   * @param oldName the name of the existing binding; may not be empty
   * @param newName the name of the new binding; may not be empty
   * @exception NameAlreadyBoundException if newName is already bound
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void rename(Name oldName, Name newName) throws NamingException {
    Object value = lookup(oldName);
    bind(newName, value);
    unbind(oldName);
  }

  /**
   * Binds a new name to the object bound to an old name, and unbinds the old name.
   *
   * @param oldName the name of the existing binding; may not be empty
   * @param newName the name of the new binding; may not be empty
   * @exception NameAlreadyBoundException if newName is already bound
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void rename(String oldName, String newName) throws NamingException {
    rename(new CompositeName(oldName), new CompositeName(newName));
  }

  /**
   * Enumerates the names bound in the named context, along with the class names of objects bound to
   * them. The contents of any subcontexts are not included.
   *
   * <p>If a binding is added to or removed from this context, its effect on an enumeration
   * previously returned is undefined.
   *
   * @param name the name of the context to list
   * @return an enumeration of the names and class names of the bindings in this context. Each
   *     element of the enumeration is of type NameClassPair.
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
    // Removing empty parts
    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) {
      return new NamingContextEnumeration(bindings.values().iterator());
    }

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (entry.type != NamingEntry.CONTEXT) {
      throw new NamingException(sm.getString("namingContext.contextExpected"));
    }
    return ((Context) entry.value).list(name.getSuffix(1));
  }

  /**
   * Enumerates the names bound in the named context, along with the class names of objects bound to
   * them.
   *
   * @param name the name of the context to list
   * @return an enumeration of the names and class names of the bindings in this context. Each
   *     element of the enumeration is of type NameClassPair.
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
    return list(new CompositeName(name));
  }

  /**
   * Enumerates the names bound in the named context, along with the objects bound to them. The
   * contents of any subcontexts are not included.
   *
   * <p>If a binding is added to or removed from this context, its effect on an enumeration
   * previously returned is undefined.
   *
   * @param name the name of the context to list
   * @return an enumeration of the bindings in this context. Each element of the enumeration is of
   *     type Binding.
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
    // Removing empty parts
    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) {
      return new NamingContextBindingsEnumeration(bindings.values().iterator(), this);
    }

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (entry.type != NamingEntry.CONTEXT) {
      throw new NamingException(sm.getString("namingContext.contextExpected"));
    }
    return ((Context) entry.value).listBindings(name.getSuffix(1));
  }

  /**
   * Enumerates the names bound in the named context, along with the objects bound to them.
   *
   * @param name the name of the context to list
   * @return an enumeration of the bindings in this context. Each element of the enumeration is of
   *     type Binding.
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
    return listBindings(new CompositeName(name));
  }

  /**
   * Destroys the named context and removes it from the namespace. Any attributes associated with
   * the name are also removed. Intermediate contexts are not destroyed.
   *
   * <p>This method is idempotent. It succeeds even if the terminal atomic name is not bound in the
   * target context, but throws NameNotFoundException if any of the intermediate contexts do not
   * exist.
   *
   * <p>In a federated naming system, a context from one naming system may be bound to a name in
   * another. One can subsequently look up and perform operations on the foreign context using a
   * composite name. However, an attempt destroy the context using this composite name will fail
   * with NotContextException, because the foreign context is not a "subcontext" of the context in
   * which it is bound. Instead, use unbind() to remove the binding of the foreign context.
   * Destroying the foreign context requires that the destroySubcontext() be performed on a context
   * from the foreign context's "native" naming system.
   *
   * @param name the name of the context to be destroyed; may not be empty
   * @exception NameNotFoundException if an intermediate context does not exist
   * @exception NotContextException if the name is bound but does not name a context, or does not
   *     name a context of the appropriate type
   */
  @Override
  public void destroySubcontext(Name name) throws NamingException {

    if (!checkWritable()) {
      return;
    }

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) throw new NamingException(sm.getString("namingContext.invalidName"));

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (name.size() > 1) {
      if (entry.type == NamingEntry.CONTEXT) {
        ((Context) entry.value).destroySubcontext(name.getSuffix(1));
      } else {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
    } else {
      if (entry.type == NamingEntry.CONTEXT) {
        ((Context) entry.value).close();
        bindings.remove(name.get(0));
      } else {
        throw new NotContextException(sm.getString("namingContext.contextExpected"));
      }
    }
  }

  /**
   * Destroys the named context and removes it from the namespace.
   *
   * @param name the name of the context to be destroyed; may not be empty
   * @exception NameNotFoundException if an intermediate context does not exist
   * @exception NotContextException if the name is bound but does not name a context, or does not
   *     name a context of the appropriate type
   */
  @Override
  public void destroySubcontext(String name) throws NamingException {
    destroySubcontext(new CompositeName(name));
  }

  /**
   * Creates and binds a new context. Creates a new context with the given name and binds it in the
   * target context (that named by all but terminal atomic component of the name). All intermediate
   * contexts and the target context must already exist.
   *
   * @param name the name of the context to create; may not be empty
   * @return the newly created context
   * @exception NameAlreadyBoundException if name is already bound
   * @exception javax.naming.directory.InvalidAttributesException if creation of the sub-context
   *     requires specification of mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Context createSubcontext(Name name) throws NamingException {
    if (!checkWritable()) {
      return null;
    }

    NamingContext newContext = new NamingContext(env, this.name);
    bind(name, newContext);

    newContext.setExceptionOnFailedWrite(getExceptionOnFailedWrite());

    return newContext;
  }

  /**
   * Creates and binds a new context.
   *
   * @param name the name of the context to create; may not be empty
   * @return the newly created context
   * @exception NameAlreadyBoundException if name is already bound
   * @exception javax.naming.directory.InvalidAttributesException if creation of the sub-context
   *     requires specification of mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Context createSubcontext(String name) throws NamingException {
    return createSubcontext(new CompositeName(name));
  }

  /**
   * Retrieves the named object, following links except for the terminal atomic component of the
   * name. If the object bound to name is not a link, returns the object itself.
   *
   * @param name the name of the object to look up
   * @return the object bound to name, not following the terminal link (if any).
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Object lookupLink(Name name) throws NamingException {
    return lookup(name, false);
  }

  /**
   * Retrieves the named object, following links except for the terminal atomic component of the
   * name.
   *
   * @param name the name of the object to look up
   * @return the object bound to name, not following the terminal link (if any).
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Object lookupLink(String name) throws NamingException {
    return lookup(new CompositeName(name), false);
  }

  /**
   * Retrieves the parser associated with the named context. In a federation of namespaces,
   * different naming systems will parse names differently. This method allows an application to get
   * a parser for parsing names into their atomic components using the naming convention of a
   * particular naming system. Within any single naming system, NameParser objects returned by this
   * method must be equal (using the equals() test).
   *
   * @param name the name of the context from which to get the parser
   * @return a name parser that can parse compound names into their atomic components
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NameParser getNameParser(Name name) throws NamingException {

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) return nameParser;

    if (name.size() > 1) {
      Object obj = bindings.get(name.get(0));
      if (obj instanceof Context) {
        return ((Context) obj).getNameParser(name.getSuffix(1));
      } else {
        throw new NotContextException(sm.getString("namingContext.contextExpected"));
      }
    }

    return nameParser;
  }

  /**
   * Retrieves the parser associated with the named context.
   *
   * @param name the name of the context from which to get the parser
   * @return a name parser that can parse compound names into their atomic components
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public NameParser getNameParser(String name) throws NamingException {
    return getNameParser(new CompositeName(name));
  }

  /**
   * Composes the name of this context with a name relative to this context.
   *
   * <p>Given a name (name) relative to this context, and the name (prefix) of this context relative
   * to one of its ancestors, this method returns the composition of the two names using the syntax
   * appropriate for the naming system(s) involved. That is, if name names an object relative to
   * this context, the result is the name of the same object, but relative to the ancestor context.
   * None of the names may be null.
   *
   * @param name a name relative to this context
   * @param prefix the name of this context relative to one of its ancestors
   * @return the composition of prefix and name
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Name composeName(Name name, Name prefix) throws NamingException {
    prefix = (Name) prefix.clone();
    return prefix.addAll(name);
  }

  /**
   * Composes the name of this context with a name relative to this context.
   *
   * @param name a name relative to this context
   * @param prefix the name of this context relative to one of its ancestors
   * @return the composition of prefix and name
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public String composeName(String name, String prefix) throws NamingException {
    return prefix + "/" + name;
  }

  /**
   * Adds a new environment property to the environment of this context. If the property already
   * exists, its value is overwritten.
   *
   * @param propName the name of the environment property to add; may not be null
   * @param propVal the value of the property to add; may not be null
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Object addToEnvironment(String propName, Object propVal) throws NamingException {
    return env.put(propName, propVal);
  }

  /**
   * Removes an environment property from the environment of this context.
   *
   * @param propName the name of the environment property to remove; may not be null
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Object removeFromEnvironment(String propName) throws NamingException {
    return env.remove(propName);
  }

  /**
   * Retrieves the environment in effect for this context. See class description for more details on
   * environment properties. The caller should not make any changes to the object returned: their
   * effect on the context is undefined. The environment of this context may be changed using
   * addToEnvironment() and removeFromEnvironment().
   *
   * @return the environment of this context; never null
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public Hashtable<?, ?> getEnvironment() throws NamingException {
    return env;
  }

  /**
   * Closes this context. This method releases this context's resources immediately, instead of
   * waiting for them to be released automatically by the garbage collector. This method is
   * idempotent: invoking it on a context that has already been closed has no effect. Invoking any
   * other method on a closed context is not allowed, and results in undefined behaviour.
   *
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public void close() throws NamingException {
    if (!checkWritable()) {
      return;
    }
    env.clear();
  }

  /**
   * Retrieves the full name of this context within its own namespace.
   *
   * <p>Many naming services have a notion of a "full name" for objects in their respective
   * namespaces. For example, an LDAP entry has a distinguished name, and a DNS record has a fully
   * qualified name. This method allows the client application to retrieve this name. The string
   * returned by this method is not a JNDI composite name and should not be passed directly to
   * context methods. In naming systems for which the notion of full name does not make sense,
   * OperationNotSupportedException is thrown.
   *
   * @return this context's name in its own namespace; never null
   * @exception OperationNotSupportedException if the naming system does not have the notion of a
   *     full name
   * @exception NamingException if a naming exception is encountered
   */
  @Override
  public String getNameInNamespace() throws NamingException {
    throw new OperationNotSupportedException(sm.getString("namingContext.noAbsoluteName"));
    // FIXME ?
  }

  // ------------------------------------------------------ Protected Methods

  /**
   * Retrieves the named object.
   *
   * @param name the name of the object to look up
   * @param resolveLinks If true, the links will be resolved
   * @return the object bound to name
   * @exception NamingException if a naming exception is encountered
   */
  protected Object lookup(Name name, boolean resolveLinks) throws NamingException {

    // Removing empty parts
    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) {
      // If name is empty, a newly allocated naming context is returned
      return new NamingContext(env, this.name, bindings);
    }

    NamingEntry entry = bindings.get(name.get(0));

    if (entry == null) {
      throw new NameNotFoundException(
          sm.getString("namingContext.nameNotBound", name, name.get(0)));
    }

    if (name.size() > 1) {
      // If the size of the name is greater that 1, then we go through a
      // number of subcontexts.
      if (entry.type != NamingEntry.CONTEXT) {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
      return ((Context) entry.value).lookup(name.getSuffix(1));
    } else {
      if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) {
        String link = ((LinkRef) entry.value).getLinkName();
        if (link.startsWith(".")) {
          // Link relative to this context
          return lookup(link.substring(1));
        } else {
          return (new InitialContext(env)).lookup(link);
        }
      } else if (entry.type == NamingEntry.REFERENCE) {
        try {
          // TODO ÐèѧϰNamingManager
          Object obj = NamingManager.getObjectInstance(entry.value, name, this, env);
          if (entry.value instanceof ResourceRef) {
            boolean singleton =
                Boolean.parseBoolean(
                    (String) ((ResourceRef) entry.value).get("singleton").getContent());
            if (singleton) {
              entry.type = NamingEntry.ENTRY;
              entry.value = obj;
            }
          }
          return obj;
        } catch (NamingException e) {
          throw e;
        } catch (Exception e) {
          log.warn(sm.getString("namingContext.failResolvingReference"), e);
          throw new NamingException(e.getMessage());
        }
      } else {
        return entry.value;
      }
    }
  }

  /**
   * Binds a name to an object. All intermediate contexts and the target context (that named by all
   * but terminal atomic component of the name) must already exist.
   *
   * @param name the name to bind; may not be empty
   * @param obj the object to bind; possibly null
   * @param rebind if true, then perform a rebind (ie, overwrite)
   * @exception NameAlreadyBoundException if name is already bound
   * @exception javax.naming.directory.InvalidAttributesException if object did not supply all
   *     mandatory attributes
   * @exception NamingException if a naming exception is encountered
   */
  protected void bind(Name name, Object obj, boolean rebind) throws NamingException {

    if (!checkWritable()) {
      return;
    }

    while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1);
    if (name.isEmpty()) throw new NamingException(sm.getString("namingContext.invalidName"));

    NamingEntry entry = bindings.get(name.get(0));

    if (name.size() > 1) {
      if (entry == null) {
        throw new NameNotFoundException(
            sm.getString("namingContext.nameNotBound", name, name.get(0)));
      }
      if (entry.type == NamingEntry.CONTEXT) {
        if (rebind) {
          ((Context) entry.value).rebind(name.getSuffix(1), obj);
        } else {
          ((Context) entry.value).bind(name.getSuffix(1), obj);
        }
      } else {
        throw new NamingException(sm.getString("namingContext.contextExpected"));
      }
    } else {
      if ((!rebind) && (entry != null)) {
        throw new NameAlreadyBoundException(
            sm.getString("namingContext.alreadyBound", name.get(0)));
      } else {
        // Getting the type of the object and wrapping it within a new
        // NamingEntry
        Object toBind = NamingManager.getStateToBind(obj, name, this, env);
        if (toBind instanceof Context) {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.CONTEXT);
        } else if (toBind instanceof LinkRef) {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.LINK_REF);
        } else if (toBind instanceof Reference) {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.REFERENCE);
        } else if (toBind instanceof Referenceable) {
          toBind = ((Referenceable) toBind).getReference();
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.REFERENCE);
        } else {
          entry = new NamingEntry(name.get(0), toBind, NamingEntry.ENTRY);
        }
        bindings.put(name.get(0), entry);
      }
    }
  }

  /** Returns true if writing is allowed on this context. */
  protected boolean isWritable() {
    return ContextAccessController.isWritable(name);
  }

  /** Throws a naming exception is Context is not writable. */
  protected boolean checkWritable() throws NamingException {
    if (isWritable()) {
      return true;
    } else {
      if (exceptionOnFailedWrite) {
        throw new javax.naming.OperationNotSupportedException(
            sm.getString("namingContext.readOnly"));
      }
    }
    return false;
  }
}
Example #16
0
/**
 * Context represent a Web Application as specified by Servlet Specs. The implementation is a
 * repository for all the properties defined in web.xml and tomcat specific properties.
 *
 * @author James Duncan Davidson [[email protected]]
 * @author James Todd [[email protected]]
 * @author Jason Hunter [[email protected]]
 * @author Harish Prabandham
 * @author [email protected]
 * @author Gal Shachor [email protected]
 * @author Arieh Markel [[email protected]]
 */
public class Context {
  private static StringManager sm = StringManager.getManager("org.apache.tomcat.core");

  // -------------------- internal properties
  // context "id"
  private String path = "";
  private String docBase;

  // Absolute path to docBase if file-system based
  private String absPath;
  // internal state / related objects
  private ContextManager contextM;
  private ServletContext contextFacade;
  private boolean crossContext = true;
  private ServletLoader servletL;
  boolean reloadable = true; // XXX change default to false after testing

  private Hashtable attributes = new Hashtable();

  private File workDir;

  // Security Permissions for webapps and jsp for this context
  Object perms = null;
  Object protectionDomain;

  //    private RequestSecurityProvider rsProvider;

  // Servlets loaded by this context( String->ServletWrapper )
  private Hashtable servlets = new Hashtable();

  // -------------------- from web.xml
  private Hashtable initializationParameters = new Hashtable();
  // all welcome files that are added are treated as "system default"
  private boolean expectUserWelcomeFiles = false;
  private Vector welcomeFiles = new Vector();
  private Hashtable errorPages = new Hashtable();
  private String description = null;
  private boolean isDistributable = false;
  private MimeMap mimeTypes = new MimeMap();
  private int sessionTimeOut = -1;

  // taglibs
  Hashtable tagLibs = new Hashtable();
  // Env entries
  Hashtable envEntryTypes = new Hashtable();
  Hashtable envEntryValues = new Hashtable();

  // Maps specified in web.xml ( String url -> ServletWrapper  )
  private Hashtable mappings = new Hashtable();
  Hashtable constraints = new Hashtable();

  Hashtable containers = new Hashtable();

  Container defaultContainer = null; // generalization, will replace most of the
  // functionality. By using a default container we avoid a lot of checkings
  // and speed up searching, and we can get rid of special properties.
  private ServletWrapper defaultServlet = null;

  // Authentication properties
  String authMethod;
  String realmName;
  String formLoginPage;
  String formErrorPage;

  int debug = 0;
  // are servlets allowed to access internal objects?
  boolean trusted = false;
  String vhost = null;
  Vector vhostAliases = new Vector();
  FacadeManager facadeM;

  public Context() {
    defaultContainer = new Container();
    defaultContainer.setContext(this);
    defaultContainer.setPath(null); // default container
  }

  /** Every context is associated with a facade */
  public ServletContext getFacade() {
    if (contextFacade == null) contextFacade = getFacadeManager().createServletContextFacade(this);
    return contextFacade;
  }

  // -------------------- Settable context properties --------------------
  // -------------------- Required properties
  public ContextManager getContextManager() {
    return contextM;
  }

  public void setContextManager(ContextManager cm) {
    contextM = cm;
  }

  public boolean getCrossContext() {
    return (this.crossContext);
  }

  public void setCrossContext(boolean crossContext) {
    this.crossContext = crossContext;
  }

  public FacadeManager getFacadeManager() {
    if (facadeM == null) {
      /* XXX make it configurable
       */
      facadeM = new SimpleFacadeManager(this);
    }
    return facadeM;
  }

  /** Base URL for this context */
  public String getPath() {
    return path;
  }

  /** Base URL for this context */
  public void setPath(String path) {
    // config believes that the root path is called "/",
    //
    if ("/".equals(path)) path = "";
    this.path = path;
  }

  /**
   * DocBase points to the web application files.
   *
   * <p>There is no restriction on the syntax and content of DocBase, it's up to the various modules
   * to interpret this and use it. For example, to serve from a war file you can use war: protocol,
   * and set up War interceptors.
   *
   * <p>"Basic" tomcat treats it as a file ( either absolute or relative to the CM home ).
   *
   * <p>If docBase is relative assume it is relative to the context manager home.
   */
  public void setDocBase(String docB) {
    this.docBase = docB;
  }

  public String getDocBase() {
    return docBase;
  }

  /** Return the absolute path for the docBase, if we are file-system based, null otherwise. */
  public String getAbsolutePath() {
    if (absPath != null) return absPath;

    if (FileUtil.isAbsolute(docBase)) absPath = docBase;
    else absPath = contextM.getHome() + File.separator + docBase;
    try {
      absPath = new File(absPath).getCanonicalPath();
    } catch (IOException npe) {
    }
    return absPath;
  }

  // -------------------- Tomcat specific properties
  // workaround for XmlMapper unable to set anything but strings
  public void setReloadable(String s) {
    reloadable = new Boolean(s).booleanValue();
  }

  public void setReloadable(boolean b) {
    reloadable = b;
  }

  /** Should we reload servlets ? */
  public boolean getReloadable() {
    return reloadable;
  }

  // -------------------- Web.xml properties --------------------

  public Enumeration getWelcomeFiles() {
    return welcomeFiles.elements();
  }

  /**
   * @deprecated It is used as a hack to allow web.xml override default welcome files. Tomcat will
   *     first load the "default" web.xml and then this file.
   */
  public void removeWelcomeFiles() {
    if (!this.welcomeFiles.isEmpty()) this.welcomeFiles.removeAllElements();
  }

  /**
   * If any new welcome file is added, remove the old list of welcome files and start a new one.
   * This is used as a hack to allow a default web.xml file to specifiy welcome files. We should use
   * a better mechanism!
   */
  public void expectUserWelcomeFiles() {
    expectUserWelcomeFiles = true;
  }

  public void addWelcomeFile(String s) {
    // user specified at least one user welcome file, remove the system
    // files
    if (s == null) return;
    s = s.trim();
    if (s.length() == 0) return;
    if (expectUserWelcomeFiles) {
      removeWelcomeFiles();
      expectUserWelcomeFiles = false;
    }
    welcomeFiles.addElement(s);
  }

  /** Add a taglib declaration for this context */
  public void addTaglib(String uri, String location) {
    //	System.out.println("Add taglib " + uri + "  " + location );
    tagLibs.put(uri, location);
  }

  public String getTaglibLocation(String uri) {
    return (String) tagLibs.get(uri);
  }

  public Enumeration getTaglibs() {
    return tagLibs.keys();
  }

  /** Add Env-entry to this context */
  public void addEnvEntry(String name, String type, String value, String description) {
    System.out.println("Add env-entry " + name + "  " + type + " " + value + " " + description);
    if (name == null || type == null) throw new IllegalArgumentException();
    envEntryTypes.put(name, type);
    if (value != null) envEntryValues.put(name, value);
  }

  public String getEnvEntryType(String name) {
    return (String) envEntryTypes.get(name);
  }

  public String getEnvEntryValue(String name) {
    return (String) envEntryValues.get(name);
  }

  public Enumeration getEnvEntries() {
    return envEntryTypes.keys();
  }

  public String getInitParameter(String name) {
    return (String) initializationParameters.get(name);
  }

  /** @deprecated use addInitParameter */
  public void setInitParameter(String name, String value) {
    initializationParameters.put(name, value);
  }

  public void addInitParameter(String name, String value) {
    initializationParameters.put(name, value);
  }

  public Enumeration getInitParameterNames() {
    return initializationParameters.keys();
  }

  public Object getAttribute(String name) {
    if (name.startsWith("org.apache.tomcat")) {
      // XXX XXX XXX XXX Security - servlets may get too much access !!!
      // right now we don't check because we need JspServlet to
      // be able to access classloader and classpath

      if (name.equals("org.apache.tomcat.jsp_classpath")) {
        String cp = getServletLoader().getClassPath();
        return cp;
      }
      if (name.equals("org.apache.tomcat.protection_domain")) {
        return getProtectionDomain();
      }
      if (name.equals("org.apache.tomcat.classloader")) {
        return this.getServletLoader().getClassLoader();
      }
      if (name.equals(FacadeManager.FACADE_ATTRIBUTE)) {
        if (!allowAttribute(name)) return null;
        return this.getFacadeManager();
      }
      return null; // org.apache.tomcat namespace is reserved in tomcat
    } else {
      Object o = attributes.get(name);
      return attributes.get(name);
    }
  }

  public Enumeration getAttributeNames() {
    return attributes.keys();
  }

  public void setAttribute(String name, Object object) {
    attributes.put(name, object);
  }

  public void removeAttribute(String name) {
    attributes.remove(name);
  }

  public String getDescription() {
    return this.description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public void setIcon(String icon) {}

  public boolean isDistributable() {
    return this.isDistributable;
  }

  public void setDistributable(boolean isDistributable) {
    this.isDistributable = isDistributable;
  }

  public void setDistributable(String s) {
    // XXX
  }

  public int getSessionTimeOut() {
    return this.sessionTimeOut;
  }

  public void setSessionTimeOut(int sessionTimeOut) {
    this.sessionTimeOut = sessionTimeOut;
  }

  public FileNameMap getMimeMap() {
    return mimeTypes;
  }

  public void addContentType(String ext, String type) {
    mimeTypes.addContentType(ext, type);
  }

  public String getErrorPage(int errorCode) {
    return getErrorPage(String.valueOf(errorCode));
  }

  public void addErrorPage(String errorType, String value) {
    this.errorPages.put(errorType, value);
  }

  public String getErrorPage(String errorCode) {
    return (String) errorPages.get(errorCode);
  }

  /** Authentication method, if any specified */
  public String getAuthMethod() {
    return authMethod;
  }

  /** Realm to be used */
  public String getRealmName() {
    return realmName;
  }

  public String getFormLoginPage() {
    return formLoginPage;
  }

  public String getFormErrorPage() {
    return formErrorPage;
  }

  public void setFormLoginPage(String page) {
    formLoginPage = page;
  }

  public void setFormErrorPage(String page) {
    formErrorPage = page;
  }

  public void setLoginConfig(
      String authMethod, String realmName, String formLoginPage, String formErrorPage) {
    // 	System.out.println("Login config: " + authMethod + " " + realmName + " " +
    // 			   formLoginPage + " " + formErrorPage);
    this.authMethod = authMethod;
    this.realmName = realmName;
    this.formLoginPage = formLoginPage;
    this.formErrorPage = formErrorPage;
  }

  // -------------------- Mappings --------------------

  /**
   * Maps a named servlet to a particular path or extension. If the named servlet is unregistered,
   * it will be added and subsequently mapped.
   *
   * <p>Note that the order of resolution to handle a request is:
   *
   * <p>exact mapped servlet (eg /catalog) prefix mapped servlets (eg /foo/bar/*) extension mapped
   * servlets (eg *jsp) default servlet
   */
  public void addServletMapping(String path, String servletName) throws TomcatException {
    if (mappings.get(path) != null) {
      log("Removing duplicate " + path + " -> " + mappings.get(path));
      mappings.remove(path);
      Container ct = (Container) containers.get(path);
      removeContainer(ct);
    }
    ServletWrapper sw = (ServletWrapper) servlets.get(servletName);
    if (sw == null) {
      // Workaround for frequent "bug" in web.xmls
      // Declare a default mapping
      log("Mapping with unregistered servlet " + servletName);
      sw = addServlet(servletName, servletName);
    }
    if ("/".equals(path)) defaultServlet = sw;

    mappings.put(path, sw);

    Container map = new Container();
    map.setContext(this);
    map.setHandler(sw);
    map.setPath(path);
    contextM.addContainer(map);
    containers.put(path, map);
  }

  /**
   * Will add a new security constraint: For all paths: if( match(path) && match(method) && match(
   * transport ) ) then require("roles")
   *
   * <p>This is equivalent with adding a Container with the path, method and transport. If the
   * container will be matched, the request will have to pass the security constraints.
   */
  public void addSecurityConstraint(
      String path[], String methods[], String roles[], String transport) throws TomcatException {
    for (int i = 0; i < path.length; i++) {
      Container ct = new Container();
      ct.setContext(this);
      ct.setTransport(transport);
      ct.setRoles(roles);
      ct.setPath(path[i]);
      ct.setMethods(methods);

      // XXX check if exists, merge if true.
      constraints.put(path[i], ct);
      // contextM.addSecurityConstraint( this, path[i], ct);
      contextM.addContainer(ct);
    }
  }

  public Enumeration getContainers() {
    return containers.elements();
  }

  public Enumeration getContainerLocations() {
    return containers.keys();
  }

  public Container getContainer(String path) {
    return (Container) containers.get(path);
  }

  // return the container associated with this context -
  // which is also the default container
  public Container getContainer() {
    return defaultContainer;
  }

  public void removeContainer(Container ct) {
    containers.remove(ct.getPath());
  }

  //     public ServletWrapper getDefaultServlet() {
  // 	if( defaultServlet==null)
  // 	    defaultServlet=getServletByName(Constants.DEFAULT_SERVLET_NAME );
  // 	return defaultServlet;
  //     }

  // -------------------- Servlets management --------------------

  // XXX do we need that ??
  /** Remove the servlet with a specific name */
  public void removeServletByName(String servletName) throws TomcatException {
    servlets.remove(servletName);
  }

  public ServletWrapper getServletByName(String servletName) {
    return (ServletWrapper) servlets.get(servletName);
  }

  /**
   * Add a servlet with the given name to the container. The servlet will be loaded by the
   * container's class loader and instantiated using the given class name.
   *
   * <p>Called to add a new servlet from web.xml
   */
  public void addServlet(ServletWrapper wrapper) throws TomcatException {
    wrapper.setContext(this);
    String name = wrapper.getServletName();
    //	System.out.println("Adding servlet " + name  + " " + wrapper);
    // check for duplicates
    if (servlets.get(name) != null) {
      log("Removing duplicate servlet " + name + " " + wrapper);
      removeServletByName(name);
      //	    getServletByName(name).destroy();
    }
    servlets.put(name, wrapper);
  }

  public ServletWrapper addServlet(String name, String classN) throws TomcatException {
    ServletWrapper sw = new ServletWrapper();
    sw.setContext(this);

    sw.setServletName(name);
    if (classN.startsWith("/")) {
      sw.setPath(classN);
    } else {
      sw.setServletClass(classN);
    }
    addServlet(sw);
    return sw;
  }

  public Enumeration getServletNames() {
    return servlets.keys();
  }

  // -------------------- Loading and sessions --------------------
  public void setServletLoader(ServletLoader loader) {
    this.servletL = loader;
  }

  public ServletLoader getServletLoader() {
    return servletL;
  }

  /* -------------------- Utils  -------------------- */
  public void setDebug(int level) {
    if (level > 0) log("Set debug to " + level);
    debug = level;
  }

  public void setDebug(String level) {
    try {
      setDebug(Integer.parseInt(level));
    } catch (Exception e) {
      log("Trying to set debug to '" + level + "':", e, Logger.ERROR);
    }
  }

  public int getDebug() {
    return debug;
  }

  // ------------------- Logging ---------------

  LogHelper loghelper = new LogHelper("tc_log", this);
  LogHelper loghelperServlet = new LogHelper("servlet_log", null);

  /** Internal log method */
  public final void log(String msg) {
    loghelper.log(msg);
  }

  /** Internal log method */
  public void log(String msg, Throwable t) {
    loghelper.log(msg, t);
  }

  /** Internal log method */
  public void log(String msg, Throwable t, int level) {
    loghelper.log(msg, t, level);
  }

  /** User-level log method ( called from a servlet) */
  public void logServlet(String msg, Throwable t) {
    msg = ("path=\"" + path + "\" :" + msg);
    loghelperServlet.log(msg, t);
  }

  public String toString() {
    return "Ctx( " + (vhost == null ? "" : vhost + ":") + path + " )";
  }

  // -------------------- Facade methods --------------------

  public Context getContext(String path) {
    if (!path.startsWith("/")) {
      return null; // according to spec, null is returned
      // if we can't  return a servlet, so it's more probable
      // servlets will check for null than IllegalArgument
    }
    // Return null if cross context lookups are not allowed
    if (!crossContext) return null;
    // absolute path
    Request lr = contextM.createRequest(path);
    if (vhost != null) lr.setServerName(vhost);
    getContextManager().processRequest(lr);
    return lr.getContext();
  }

  /**
   * Implements getResource() See getRealPath(), it have to be local to the current Context - and
   * can't go to a sub-context. That means we don't need any overhead.
   */
  public URL getResource(String rpath) throws MalformedURLException {
    if (rpath == null) return null;

    if (URLUtil.hasEscape(rpath)) return null;

    URL url = null;
    String absPath = getAbsolutePath();

    if ("".equals(rpath)) return new URL("file", null, 0, absPath);

    if (!rpath.startsWith("/")) rpath = "/" + rpath;

    String realPath = FileUtil.safePath(absPath, rpath);
    if (realPath == null) {
      log("Unsafe path " + absPath + " " + rpath);
      return null;
    }

    try {
      url = new URL("file", null, 0, realPath);
      if (debug > 9) log("getResourceURL=" + url + " request=" + rpath);
      return url;
    } catch (IOException ex) {
      ex.printStackTrace();
      return null;
    }
  }

  /**
   * According to Servlet 2.2 the real path is interpreted as relative to the current web app and
   * _cannot_ go outside the box. If your intention is different or want the "other" behavior you'll
   * have to first call getContext(path) and call getRealPath() on the result context ( if any - the
   * server may disable that from security reasons !). XXX find out how can we find the context path
   * in order to remove it from the path - that's the only way a user can do that unless he have
   * prior knowledge of the mappings !
   */
  public String getRealPath(String path) {
    String base = getAbsolutePath();
    if (path == null) path = "";

    String realPath = FileUtil.safePath(base, path);
    // No need for a sub-request, that's a great simplification
    // in servlet space.

    // Important: that's different from what some people might
    // expect and how other server APIs work, but that's how it's
    // specified in 2.2. From a security point of view that's very
    // good, it keeps inter-webapp communication under control.

    if (debug > 5) {
      log("Get real path " + path + " " + realPath + " " + base);
    }
    return realPath;
  }

  /**
   * method to return the Localized version of the file whose name is passed as an argument. This
   * corresponds to "file" type localization resource lookup mechanism.
   *
   * <p>The method performs a resource lookup in a manner similar to the one specified by
   * java.util.ResourceBundle.
   *
   * <p>In the case of 'typed' files (files whose name is [file].[ftype]) search for localized
   * versions of the file are looked for:
   *
   * <p>file + "_" + language1 + "_" + country1 + "_" + variant1 + "." + ftype file + "_" +
   * language1 + "_" + country1 + "." + ftype file + "_" + language1 + "." + ftype file + "_" +
   * language2 + "_" + country2 + "_" + variant2 "." + ftype file + "_" + language2 + "_" + country2
   * "." + ftype file + "_" + language2 + "." + ftype file + "." + ftype
   *
   * <p>Where language1, country1, variant1 are associated with the Locale passed as an argument and
   * language2, country2, variant are associated with the default Locale passed as argument.
   *
   * <p>For example, if the preferred Locale is <CODE>es_AR_POSIX</CODE> and the default Locale
   * passed is <CODE>fr_CA_WIN</CODE>, and the requested pathname is <CODE>/foo/bar/index.html
   * </CODE>, then a search for the following localized versions of that file will be done, in
   * order:
   *
   * <UL>
   *   <LI>/foo/bar/index_es_AR_POSIX.html
   *   <LI>/foo/bar/index_es_AR.html
   *   <LI>/foo/bar/index_es.html
   *   <LI>/foo/bar/index_fr_CA_WIN.html
   *   <LI>/foo/bar/index_fr.html
   *   <LI>/foo/bar/index.html
   * </UL>
   *
   * If the resource passed has no 'ftype' component, then the same rules above apply, with the
   * exception that '.' + ftype are not concatenated.
   *
   * @param path the pathname for the resource whose localized version we are seeking
   * @param loc the Locale we are interested in.
   * @param fbLoc the fallback Locale to use if unsuccessful
   * @return a String with the path of the "best localized match" for the file whose path has been
   *     passed as argument.
   */
  public String getRealPath(String path, Locale reqLocale, Locale fbLocale) {
    return getRealPath(path, reqLocale, fbLocale, "file");
  }

  /**
   * method to return the Localized version of the file whose name is passed as an argument. The
   * localization is done based on localization subdirectories under the docBase.
   *
   * <p>The method performs a resource lookup in a manner similar to the one used for JavaHelp
   * resources.
   *
   * <p>Search for localized versions of the file are looked for:
   *
   * <p><docBase> + "/" + language1 + "_" + country1 + "_" + variant1 + file <docBase> + "/" +
   * language1 + "_" + country1 + file <docBase> + "/" + language1 + file <docBase> + "/" +
   * language2 + "_" + country2 + "_" + variant1 + file <docBase> + "/" + language2 + "_" + country2
   * + file <docBase> + "/" + language2 + file <docBase> + file
   *
   * <p>Where language1, country1, variant1 are associated with the Locale passed as an argument and
   * language2, country2, variant are associated with the fallback Locale passed as argument.
   *
   * @param path the pathname for the resource whose localized version we are seeking
   * @param loc the Locale we are interested in.
   * @param fbLoc the fallback Locale to use if unsuccessful
   * @param locType the type of localization required "file", "docbase"
   * @return a String with the path of the "best localized match" for the file whose path has been
   *     passed as argument.
   */
  public String getRealPath(String path, Locale reqLocale, Locale fbLocale, String locType) {
    String base = getAbsolutePath();
    if (path == null) path = "";

    String realPath = null;

    if ("file".equals(locType))
      realPath = FileUtil.getLocalizedFile(base, path, reqLocale, fbLocale);
    else if ("docbase".equals(locType))
      realPath = FileUtil.getDocBaseLocalizedFile(base, path, reqLocale, fbLocale);

    if (debug > 5) {
      log(
          "Get real path "
              + path
              + " "
              + realPath
              + " "
              + base
              + reqLocale.toString()
              + " "
              + fbLocale.toString());
    }

    return realPath;
  }

  // -------------------- Deprecated
  // tomcat specific properties
  private boolean isWorkDirPersistent = false;
  private String engineHeader = null;
  private URL documentBase;
  private URL servletBase = null;
  private boolean isInvokerEnabled = false;
  // for serving WARs directly
  private File warDir = null;
  private boolean isWARExpanded = false;
  private boolean isWARValidated = false;

  /** @deprecated */
  public boolean isInvokerEnabled() {
    return isInvokerEnabled;
  }

  /** @deprecated */
  public void setInvokerEnabled(boolean isInvokerEnabled) {
    this.isInvokerEnabled = isInvokerEnabled;
  }

  /** @deprecated */
  public boolean isWorkDirPersistent() {
    return this.isWorkDirPersistent;
  }

  /** @deprecated */
  public void setWorkDirPersistent(boolean b) {
    isWorkDirPersistent = b;
  }

  /** @deprecated */
  public File getWorkDir() {
    return workDir;
  }

  /** @deprecated */
  public void setWorkDir(File workDir) {
    this.workDir = workDir;
  }

  /**
   * Set work dir using a String property
   *
   * @deprecated
   */
  public void setWorkDirPath(String workDir) {
    this.workDir = new File(workDir);
  }

  /** @deprecated */
  public String getEngineHeader() {
    return engineHeader;
  }

  /** @deprecated */
  public void setEngineHeader(String s) {
    engineHeader = s;
  }

  //     /**  @deprecated
  //      */
  //     public void setRequestSecurityProvider(RequestSecurityProvider rsProvider) {
  // 	this.rsProvider = rsProvider;
  //     }

  //     /**  @deprecated
  //      */
  //     public RequestSecurityProvider getRequestSecurityProvider() {
  // 	return this.rsProvider;
  //     }

  /** @deprecated */
  public File getWARDir() {
    return this.warDir;
  }

  /** @deprecated */
  public void setWARDir(File f) {
    warDir = f;
  }

  /** @deprecated */
  public boolean isWARExpanded() {
    return this.isWARExpanded;
  }

  /** @deprecated */
  public void setIsWARExpanded(boolean isWARExpanded) {
    this.isWARExpanded = isWARExpanded;
  }

  /** @deprecated */
  public boolean isWARValidated() {
    return this.isWARValidated;
  }

  /** @deprecated */
  public void setIsWARValidated(boolean isWARValidated) {
    this.isWARValidated = isWARValidated;
  }

  /** @deprecated */
  public void addContextInterceptor(ContextInterceptor ci) {
    getContainer().addContextInterceptor(ci);
  }

  /** @deprecated */
  public ContextInterceptor[] getContextInterceptors() {
    return getContainer().getContextInterceptors();
  }

  /** @deprecated */
  public void addRequestInterceptor(RequestInterceptor ci) {
    getContainer().addRequestInterceptor(ci);
  }

  /** @deprecated */
  public RequestInterceptor[] getRequestInterceptors() {
    return getContainer().getRequestInterceptors();
  }

  /** Get the SecurityManager Permissions for this Context. */
  public Object getPermissions() {
    return perms;
  }

  public void setPermissions(Object o) {
    perms = o;
  }

  public Object getProtectionDomain() {
    return protectionDomain;
  }

  public void setProtectionDomain(Object o) {
    protectionDomain = o;
  }

  /**
   * @deprecated - use getDocBase and URLUtil if you need it as URL NOT USED INSIDE TOMCAT - ONLY IN
   *     OLD J2EE CONNECTORS !
   */
  public URL getDocumentBase() {
    if (documentBase == null) {
      if (docBase == null) return null;
      try {
        String absPath = docBase;

        // detect absolute path ( use the same logic in all tomcat )
        if (FileUtil.isAbsolute(docBase)) absPath = docBase;
        else absPath = contextM.getHome() + File.separator + docBase;

        try {
          absPath = new File(absPath).getCanonicalPath();
        } catch (IOException npe) {
        }

        documentBase = new URL("file", "", absPath);

      } catch (MalformedURLException ex) {
        ex.printStackTrace();
      }
    }
    return documentBase;
  }

  /** @deprecated - use setDocBase */
  public void setDocumentBase(URL s) {
    // Used only by startup, will be removed
    this.documentBase = s;
  }

  // -------------------- Virtual host support --------------------

  /** Make this context visible as part of a virtual host */
  public void setHost(String h) {
    vhost = h;
  }

  /** Return the virtual host name, or null if we are in the default context */
  public String getHost() {
    return vhost;
  }

  /**
   * Virtual host support - this context will be part of a virtual host with the specified name. You
   * should set all the aliases. XXX Not implemented
   */
  public void addHostAlias(String alias) {
    vhostAliases.addElement(alias);
  }

  public Enumeration getHostAliases() {
    return vhostAliases.elements();
  }
  // -------------------- Security - trusted code --------------------

  public void setTrusted(boolean t) {
    trusted = t;
  }

  public boolean isTrusted() {
    return trusted;
  }

  public boolean allowAttribute(String name) {
    // check if we can access this attribute.
    if (isTrusted()) return true;
    log("Illegal access to internal attribute ", null, Logger.ERROR);
    return false;
  }
}
Example #17
0
 public String id() {
   return strings.get(readShort(attributesEnd + 0xc));
 }