e)
+ {
+ _delegate = e;
+ }
+
+ public void close()
+ throws NamingException
+ {
+ }
+
+ public boolean hasMore ()
+ throws NamingException
+ {
+ return _delegate.hasNext();
+ }
+
+ public NameClassPair next()
+ throws NamingException
+ {
+ Binding b = _delegate.next();
+ return new NameClassPair(b.getName(),b.getClassName(),true);
+ }
+
+ public boolean hasMoreElements()
+ {
+ return _delegate.hasNext();
+ }
+
+ public NameClassPair nextElement()
+ {
+ Binding b = _delegate.next();
+ return new NameClassPair(b.getName(),b.getClassName(),true);
+ }
+}
\ No newline at end of file
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java
index e6dec8bbae0..da2ee7d35b0 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java
@@ -20,7 +20,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -31,7 +30,6 @@ import javax.naming.InitialContext;
import javax.naming.LinkRef;
import javax.naming.Name;
import javax.naming.NameAlreadyBoundException;
-import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
@@ -53,17 +51,8 @@ import org.eclipse.jetty.util.log.Logger;
* Notes
* All Names are expected to be Compound, not Composite.
*
- *
Usage
- *
+ *
*/
-/*
-*
-*
-* @see
-*
-*
-* @version 1.0
-*/
public class NamingContext implements Context, Cloneable, Dumpable
{
private final static Logger __log=NamingUtil.__log;
@@ -101,123 +90,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
void unbind(NamingContext ctx, Binding binding);
}
- /*------------------------------------------------*/
- /** NameEnumeration
- * Implementation of NamingEnumeration interface.
- *
- *
Notes
- * Used for returning results of Context.list();
- *
- *
Usage
- *
- */
- /*
- *
- *
- * @see
- *
- */
- public class NameEnumeration implements NamingEnumeration
- {
- Iterator _delegate;
-
- public NameEnumeration (Iterator e)
- {
- _delegate = e;
- }
-
- public void close()
- throws NamingException
- {
- }
-
- public boolean hasMore ()
- throws NamingException
- {
- return _delegate.hasNext();
- }
-
- public NameClassPair next()
- throws NamingException
- {
- Binding b = _delegate.next();
- return new NameClassPair(b.getName(),b.getClassName(),true);
- }
-
- public boolean hasMoreElements()
- {
- return _delegate.hasNext();
- }
-
- public NameClassPair nextElement()
- {
- Binding b = _delegate.next();
- return new NameClassPair(b.getName(),b.getClassName(),true);
- }
- }
-
-
-
-
-
-
- /*------------------------------------------------*/
- /** BindingEnumeration
- * Implementation of NamingEnumeration
- *
- *
Notes
- * Used to return results of Context.listBindings();
- *
- *
Usage
- *
- */
- /*
- *
- *
- * @see
- *
- */
- public class BindingEnumeration implements NamingEnumeration
- {
- Iterator _delegate;
-
- public BindingEnumeration (Iterator e)
- {
- _delegate = e;
- }
-
- public void close()
- throws NamingException
- {
- }
-
- public boolean hasMore ()
- throws NamingException
- {
- return _delegate.hasNext();
- }
-
- public Binding next()
- throws NamingException
- {
- Binding b = (Binding)_delegate.next();
- return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
- }
-
- public boolean hasMoreElements()
- {
- return _delegate.hasNext();
- }
-
- public Binding nextElement()
- {
- Binding b = (Binding)_delegate.next();
- return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
- }
- }
-
-
-
/*------------------------------------------------*/
/**
* Constructor
@@ -240,26 +112,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
- /*------------------------------------------------*/
- /**
- * Creates a new NamingContext
instance.
- *
- * @param env a Hashtable
value
- */
- public NamingContext (Hashtable env)
- {
- if (env != null)
- _env.putAll(env);
- }
-
- /*------------------------------------------------*/
- /**
- * Constructor
- *
- */
- public NamingContext ()
- {
- }
/*------------------------------------------------*/
@@ -312,8 +164,24 @@ public class NamingContext implements Context, Cloneable, Dumpable
_parser = parser;
}
+
+ public void setEnv (Hashtable env)
+ {
+ _env.clear();
+ _env.putAll(env);
+ }
+
+ public Map getBindings ()
+ {
+ return _bindings;
+ }
+ public void setBindings(Map bindings)
+ {
+ _bindings = bindings;
+ }
+
/*------------------------------------------------*/
/**
* Bind a name to an object
@@ -435,8 +303,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
ne.setRemainingName(name);
throw ne;
}
-
-
Name cname = toCanonicalName (name);
@@ -521,7 +387,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
/*------------------------------------------------*/
/**
- * Not supported
+ *
*
* @param name name of subcontext to remove
* @exception NamingException if an error occurs
@@ -536,7 +402,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
/*------------------------------------------------*/
/**
- * Not supported
+ *
*
* @param name name of subcontext to remove
* @exception NamingException if an error occurs
@@ -1128,7 +994,6 @@ public class NamingContext implements Context, Cloneable, Dumpable
ctx = binding.getObject();
-
if (ctx instanceof Reference)
{
//deference the object
@@ -1154,8 +1019,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
else
throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
- }
-
+ }
}
/*------------------------------------------------*/
@@ -1182,11 +1046,11 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param newName a Name
value
* @exception NamingException if an error occurs
*/ public void rename(String oldName,
- String newName)
- throws NamingException
- {
- throw new OperationNotSupportedException();
- }
+ String newName)
+ throws NamingException
+ {
+ throw new OperationNotSupportedException();
+ }
@@ -1247,9 +1111,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
*/
public void close ()
throws NamingException
- {
-
-
+ {
}
@@ -1362,7 +1224,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param name a Name
value
* @param obj an Object
value
*/
- protected void addBinding (Name name, Object obj) throws NameAlreadyBoundException
+ public void addBinding (Name name, Object obj) throws NameAlreadyBoundException
{
String key = name.toString();
Binding binding=new Binding (key, obj);
@@ -1394,7 +1256,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param name a Name
value
* @return a Binding
value
*/
- protected Binding getBinding (Name name)
+ public Binding getBinding (Name name)
{
return (Binding) _bindings.get(name.toString());
}
@@ -1407,13 +1269,13 @@ public class NamingContext implements Context, Cloneable, Dumpable
* @param name as a String
* @return null or the Binding
*/
- protected Binding getBinding (String name)
+ public Binding getBinding (String name)
{
return (Binding) _bindings.get(name);
}
/*------------------------------------------------*/
- protected void removeBinding (Name name)
+ public void removeBinding (Name name)
{
String key = name.toString();
if (__log.isDebugEnabled())
@@ -1455,7 +1317,7 @@ public class NamingContext implements Context, Cloneable, Dumpable
}
/* ------------------------------------------------------------ */
- private boolean isLocked()
+ public boolean isLocked()
{
if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null))
return false;
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java
index 09dcfc8f49a..d26b8475b18 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java
@@ -67,8 +67,7 @@ public class javaRootURLContext implements Context
try
{
__javaNameParser = new javaNameParser();
- __nameRoot = new NamingContext();
- __nameRoot.setNameParser(__javaNameParser);
+ __nameRoot = new NamingContext(null,null,null,__javaNameParser);
StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName());
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java
index 7c187a7166e..a915ad1917d 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java
@@ -13,36 +13,63 @@
package org.eclipse.jetty.jndi.local;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
import java.util.Properties;
+import javax.naming.Binding;
import javax.naming.CompoundName;
import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.LinkRef;
import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
+import javax.naming.NotContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.spi.NamingManager;
+import org.eclipse.jetty.jndi.BindingEnumeration;
+import org.eclipse.jetty.jndi.NameEnumeration;
import org.eclipse.jetty.jndi.NamingContext;
+import org.eclipse.jetty.jndi.NamingUtil;
+import org.eclipse.jetty.util.log.Logger;
/**
*
* localContext
*
+ * Implementation of the delegate for InitialContext for the local namespace.
+ *
*
* @version $Revision: 4780 $ $Date: 2009-03-17 16:36:08 +0100 (Tue, 17 Mar 2009) $
*
*/
public class localContextRoot implements Context
{
- private static final NamingContext __root = new NamingContext();
+ private final static Logger __log=NamingUtil.__log;
+ protected final static NamingContext __root = new NamingRoot();
private final Hashtable _env;
+
- // make a root for the static namespace local:
- static
+ static class NamingRoot extends NamingContext
{
- __root.setNameParser(new LocalNameParser());
+ public NamingRoot()
+ {
+ super (null,null,null,new LocalNameParser());
+ }
}
+
+
static class LocalNameParser implements NameParser
{
@@ -61,6 +88,19 @@ public class localContextRoot implements Context
}
}
+
+ /*
+ * Root has to use the localContextRoot's env for all operations.
+ * So, if createSubcontext in the root, use the env of the localContextRoot.
+ * If lookup binding in the root, use the env of the localContextRoot.
+ *
+ */
+
+
+
+
+
+
public static NamingContext getRoot()
{
return __root;
@@ -91,6 +131,21 @@ public class localContextRoot implements Context
return "";
}
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#destroySubcontext(javax.naming.Name)
+ */
+ public void destroySubcontext(Name name) throws NamingException
+ {
+ synchronized (__root)
+ {
+ __root.destroySubcontext(getSuffix(name));
+ }
+ }
+
+
/**
*
*
@@ -100,23 +155,12 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- __root.destroySubcontext(getSuffix(name));
- }
- }
-
- /**
- *
- *
- * @see javax.naming.Context#unbind(java.lang.String)
- */
- public void unbind(String name) throws NamingException
- {
- synchronized (__root)
- {
- __root.unbind(getSuffix(name));
+
+ destroySubcontext(__root.getNameParser("").parse(getSuffix(name)));
}
}
+
/**
*
*
@@ -127,18 +171,7 @@ public class localContextRoot implements Context
return _env;
}
- /**
- *
- *
- * @see javax.naming.Context#destroySubcontext(javax.naming.Name)
- */
- public void destroySubcontext(Name name) throws NamingException
- {
- synchronized (__root)
- {
- __root.destroySubcontext(getSuffix(name));
- }
- }
+
/**
*
@@ -149,23 +182,92 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- __root.unbind(getSuffix(name));
+ //__root.unbind(getSuffix(name));
+
+ if (name.size() == 0)
+ return;
+
+
+ if (__root.isLocked())
+ throw new NamingException ("This context is immutable");
+
+ Name cname = __root.toCanonicalName(name);
+
+ if (cname == null)
+ throw new NamingException ("Name is null");
+
+ if (cname.size() == 0)
+ throw new NamingException ("Name is empty");
+
+
+ //if no subcontexts, just unbind it
+ if (cname.size() == 1)
+ {
+ __root.removeBinding (cname);
+ }
+ else
+ {
+ //walk down the subcontext hierarchy
+ if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
+
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+ Binding binding = __root.getBinding (name.get(0));
+ if (binding == null)
+ throw new NameNotFoundException (name.get(0)+ " is not bound");
+
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+ if (ctx instanceof Context)
+ {
+ ((Context)ctx).unbind (cname.getSuffix(1));
+ }
+ else
+ throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
+ }
+
+
+
}
}
/**
*
*
- * @see javax.naming.Context#lookup(java.lang.String)
+ * @see javax.naming.Context#unbind(java.lang.String)
*/
- public Object lookup(String name) throws NamingException
+ public void unbind(String name) throws NamingException
{
- synchronized (__root)
- {
- return __root.lookup(getSuffix(name));
- }
+ unbind(__root.getNameParser("").parse(getSuffix(name)));
}
+
+
/**
*
*
@@ -175,56 +277,7 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- return __root.lookupLink(getSuffix(name));
- }
- }
-
- /**
- *
- *
- * @see javax.naming.Context#removeFromEnvironment(java.lang.String)
- */
- public Object removeFromEnvironment(String propName) throws NamingException
- {
- return _env.remove(propName);
- }
-
- /**
- *
- *
- * @see javax.naming.Context#bind(java.lang.String, java.lang.Object)
- */
- public void bind(String name, Object obj) throws NamingException
- {
- synchronized (__root)
- {
- __root.bind(getSuffix(name), obj);
- }
- }
-
- /**
- *
- *
- * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object)
- */
- public void rebind(String name, Object obj) throws NamingException
- {
- synchronized (__root)
- {
- __root.rebind(getSuffix(name), obj);
- }
- }
-
- /**
- *
- *
- * @see javax.naming.Context#lookup(javax.naming.Name)
- */
- public Object lookup(Name name) throws NamingException
- {
- synchronized (__root)
- {
- return __root.lookup(getSuffix(name));
+ return lookupLink(__root.getNameParser("").parse(getSuffix(name)));
}
}
@@ -237,10 +290,262 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- return __root.lookupLink(getSuffix(name));
+ //return __root.lookupLink(getSuffix(name));
+
+
+ Name cname = __root.toCanonicalName(name);
+
+ if (cname == null)
+ {
+ //If no name create copy of this context with same bindings, but with copy of the environment so it can be modified
+ NamingContext ctx = new NamingContext (_env, null, null, __root.getNameParser(""));
+ ctx.setBindings(__root.getBindings());
+ return ctx;
+ }
+
+ if (cname.size() == 0)
+ throw new NamingException ("Name is empty");
+
+ if (cname.size() == 1)
+ {
+ Binding binding = __root.getBinding (cname);
+ if (binding == null)
+ throw new NameNotFoundException();
+
+ Object o = binding.getObject();
+
+ //handle links by looking up the link
+ if (o instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ return NamingManager.getObjectInstance(o, cname.getPrefix(1), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ else
+ {
+ //object is either a LinkRef which we don't dereference
+ //or a plain object in which case spec says we return it
+ return o;
+ }
+ }
+
+
+ //it is a multipart name, recurse to the first subcontext
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+ Binding binding = __root.getBinding (firstComponent);
+ if (binding == null)
+ throw new NameNotFoundException ();
+
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+ if (!(ctx instanceof Context))
+ throw new NotContextException();
+
+ return ((Context)ctx).lookup (cname.getSuffix(1));
+
+
}
}
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#removeFromEnvironment(java.lang.String)
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException
+ {
+ return _env.remove(propName);
+ }
+
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#lookup(javax.naming.Name)
+ */
+ public Object lookup(Name name) throws NamingException
+ {
+ synchronized (__root)
+ {
+ //return __root.lookup(getSuffix(name));
+
+ if(__log.isDebugEnabled())__log.debug("Looking up name=\""+name+"\"");
+ Name cname = __root.toCanonicalName(name);
+
+ if ((cname == null) || (cname.size() == 0))
+ {
+ __log.debug("Null or empty name, returning copy of this context");
+ NamingContext ctx = new NamingContext (_env, null, null, __root.getNameParser(""));
+ ctx.setBindings(__root.getBindings());
+ return ctx;
+ }
+
+
+
+ if (cname.size() == 1)
+ {
+ Binding binding = __root.getBinding (cname);
+ if (binding == null)
+ {
+ NameNotFoundException nnfe = new NameNotFoundException();
+ nnfe.setRemainingName(cname);
+ throw nnfe;
+ }
+
+
+ Object o = binding.getObject();
+
+ //handle links by looking up the link
+ if (o instanceof LinkRef)
+ {
+ //if link name starts with ./ it is relative to current context
+ String linkName = ((LinkRef)o).getLinkName();
+ if (linkName.startsWith("./"))
+ return lookup (linkName.substring(2));
+ else
+ {
+ //link name is absolute
+ InitialContext ictx = new InitialContext();
+ return ictx.lookup (linkName);
+ }
+ }
+ else if (o instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ return NamingManager.getObjectInstance(o, cname, __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ else
+ return o;
+ }
+
+ //it is a multipart name, get the first subcontext
+
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+
+ Binding binding = __root.getBinding (firstComponent);
+ if (binding == null)
+ {
+ NameNotFoundException nnfe = new NameNotFoundException();
+ nnfe.setRemainingName(cname);
+ throw nnfe;
+ }
+
+ //as we have bound a reference to an object factory
+ //for the component specific contexts
+ //at "comp" we need to resolve the reference
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+ if (!(ctx instanceof Context))
+ throw new NotContextException();
+
+ return ((Context)ctx).lookup (cname.getSuffix(1));
+
+ }
+ }
+
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#lookup(java.lang.String)
+ */
+ public Object lookup(String name) throws NamingException
+ {
+ synchronized (__root)
+ {
+ return lookup(__root.getNameParser("").parse(getSuffix(name)));
+ }
+ }
+
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#bind(java.lang.String, java.lang.Object)
+ */
+ public void bind(String name, Object obj) throws NamingException
+ {
+ synchronized (__root)
+ {
+ bind(__root.getNameParser("").parse(getSuffix(name)), obj);
+
+ }
+ }
+
+
/**
*
*
@@ -250,7 +555,83 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- __root.bind(getSuffix(name), obj);
+ // __root.bind(getSuffix(name), obj);
+
+
+ if (__root.isLocked())
+ throw new NamingException ("This context is immutable");
+
+ Name cname = __root.toCanonicalName(name);
+
+ if (cname == null)
+ throw new NamingException ("Name is null");
+
+ if (cname.size() == 0)
+ throw new NamingException ("Name is empty");
+
+
+ //if no subcontexts, just bind it
+ if (cname.size() == 1)
+ {
+ //get the object to be bound
+ Object objToBind = NamingManager.getStateToBind(obj, name,this, _env);
+ // Check for Referenceable
+ if (objToBind instanceof Referenceable)
+ {
+ objToBind = ((Referenceable)objToBind).getReference();
+ }
+
+ //anything else we should be able to bind directly
+ __root.addBinding (cname, objToBind);
+ }
+ else
+ {
+ if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
+
+ //walk down the subcontext hierarchy
+ //need to ignore trailing empty "" name components
+
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+
+ Binding binding = __root.getBinding (firstComponent);
+ if (binding == null)
+ throw new NameNotFoundException (firstComponent+ " is not bound");
+
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+
+ if (ctx instanceof Context)
+ {
+ ((Context)ctx).bind (cname.getSuffix(1), obj);
+ }
+ else
+ throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
+ }
}
}
@@ -263,7 +644,105 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- __root.rebind(getSuffix(name), obj);
+ //__root.rebind(getSuffix(name), obj);
+
+
+ if (__root.isLocked())
+ throw new NamingException ("This context is immutable");
+
+ Name cname = __root.toCanonicalName(name);
+
+ if (cname == null)
+ throw new NamingException ("Name is null");
+
+ if (cname.size() == 0)
+ throw new NamingException ("Name is empty");
+
+
+ //if no subcontexts, just bind it
+ if (cname.size() == 1)
+ {
+ //check if it is a Referenceable
+ Object objToBind = NamingManager.getStateToBind(obj, name, __root, _env);
+
+ if (objToBind instanceof Referenceable)
+ {
+ objToBind = ((Referenceable)objToBind).getReference();
+ }
+ __root.removeBinding(cname);
+ __root.addBinding (cname, objToBind);
+ }
+ else
+ {
+ //walk down the subcontext hierarchy
+ if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0));
+
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+ Binding binding = __root.getBinding (name.get(0));
+ if (binding == null)
+ throw new NameNotFoundException (name.get(0)+ " is not bound");
+
+ ctx = binding.getObject();
+
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+ if (ctx instanceof Context)
+ {
+ ((Context)ctx).rebind (cname.getSuffix(1), obj);
+ }
+ else
+ throw new NotContextException ("Object bound at "+firstComponent +" is not a Context");
+ }
+ }
+ }
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object)
+ */
+ public void rebind(String name, Object obj) throws NamingException
+ {
+ synchronized (__root)
+ {
+ rebind(__root.getNameParser("").parse(getSuffix(name)), obj);
+ }
+ }
+ /**
+ *
+ *
+ * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name)
+ */
+ public void rename(Name oldName, Name newName) throws NamingException
+ {
+ synchronized (__root)
+ {
+ throw new OperationNotSupportedException();
}
}
@@ -276,7 +755,7 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- __root.rename(getSuffix(oldName), getSuffix(newName));
+ throw new OperationNotSupportedException();
}
}
@@ -289,7 +768,15 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- return __root.createSubcontext(getSuffix(name));
+ //if the subcontext comes directly off the root, use the env of the InitialContext
+ //as the root itself has no environment. Otherwise, it inherits the env of the parent
+ //Context further down the tree.
+ //NamingContext ctx = (NamingContext)__root.createSubcontext(name);
+ //if (ctx.getParent() == __root)
+ // ctx.setEnv(_env);
+ //return ctx;
+
+ return createSubcontext(__root.getNameParser("").parse(name));
}
}
@@ -301,24 +788,92 @@ public class localContextRoot implements Context
public Context createSubcontext(Name name) throws NamingException
{
synchronized (__root)
- {
- return __root.createSubcontext(getSuffix(name));
- }
- }
-
- /**
- *
- *
- * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name)
- */
- public void rename(Name oldName, Name newName) throws NamingException
- {
- synchronized (__root)
- {
- __root.rename(getSuffix(oldName), getSuffix(newName));
+ {
+ //if the subcontext comes directly off the root, use the env of the InitialContext
+ //as the root itself has no environment. Otherwise, it inherits the env of the parent
+ //Context further down the tree.
+ //NamingContext ctx = (NamingContext)__root.createSubcontext(getSuffix(name));
+ //if (ctx.getParent() == __root)
+ // ctx.setEnv(_env);
+ //return ctx;
+
+
+
+
+ if (__root.isLocked())
+ {
+ NamingException ne = new NamingException ("This context is immutable");
+ ne.setRemainingName(name);
+ throw ne;
+ }
+
+ Name cname = __root.toCanonicalName (name);
+
+ if (cname == null)
+ throw new NamingException ("Name is null");
+ if (cname.size() == 0)
+ throw new NamingException ("Name is empty");
+
+ if (cname.size() == 1)
+ {
+ //not permitted to bind if something already bound at that name
+ Binding binding = __root.getBinding (cname);
+ if (binding != null)
+ throw new NameAlreadyBoundException (cname.toString());
+
+ //make a new naming context with the root as the parent
+ Context ctx = new NamingContext ((Hashtable)_env.clone(), cname.get(0), __root, __root.getNameParser(""));
+ __root.addBinding (cname, ctx);
+ return ctx;
+ }
+
+
+ //If the name has multiple subcontexts, walk the hierarchy by
+ //fetching the first one. All intermediate subcontexts in the
+ //name must already exist.
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+ Binding binding = __root.getBinding (firstComponent);
+ if (binding == null)
+ throw new NameNotFoundException (firstComponent + " is not bound");
+
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ if(__log.isDebugEnabled())__log.debug("Object bound at "+firstComponent +" is a Reference");
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+ if (ctx instanceof Context)
+ {
+ return ((Context)ctx).createSubcontext (cname.getSuffix(1));
+ }
+ else
+ throw new NotContextException (firstComponent +" is not a Context");
}
}
+
/**
*
*
@@ -348,22 +903,10 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- return __root.list(getSuffix(name));
+ return list(__root.getNameParser("").parse(getSuffix(name)));
}
}
- /**
- *
- *
- * @see javax.naming.Context#listBindings(java.lang.String)
- */
- public NamingEnumeration listBindings(String name) throws NamingException
- {
- synchronized (__root)
- {
- return __root.listBindings(getSuffix(name));
- }
- }
/**
*
@@ -374,7 +917,64 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- return __root.list(getSuffix(name));
+ //return __root.list(getSuffix(name));
+
+
+ Name cname = __root.toCanonicalName(name);
+
+ if (cname == null)
+ {
+ List empty = Collections.emptyList();
+ return new NameEnumeration(empty.iterator());
+ }
+
+
+ if (cname.size() == 0)
+ {
+ return new NameEnumeration (__root.getBindings().values().iterator());
+ }
+
+
+
+ //multipart name
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+ Binding binding = __root.getBinding (firstComponent);
+ if (binding == null)
+ throw new NameNotFoundException ();
+
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ if(__log.isDebugEnabled())__log.debug("Dereferencing Reference for "+name.get(0));
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+ if (!(ctx instanceof Context))
+ throw new NotContextException();
+
+ return ((Context)ctx).list (cname.getSuffix(1));
+
}
}
@@ -387,10 +987,82 @@ public class localContextRoot implements Context
{
synchronized (__root)
{
- return __root.listBindings(getSuffix(name));
+ //return __root.listBindings(getSuffix(name));
+
+ Name cname = __root.toCanonicalName (name);
+
+ if (cname == null)
+ {
+ List empty = Collections.emptyList();
+ return new BindingEnumeration(empty.iterator());
+ }
+
+ if (cname.size() == 0)
+ {
+ return new BindingEnumeration (__root.getBindings().values().iterator());
+ }
+
+
+
+ //multipart name
+ String firstComponent = cname.get(0);
+ Object ctx = null;
+
+ //if a name has a leading "/" it is parsed as "" so ignore it by staying
+ //at this level in the tree
+ if (firstComponent.equals(""))
+ ctx = this;
+ else
+ {
+ //it is a non-empty name component
+ Binding binding = __root.getBinding (firstComponent);
+ if (binding == null)
+ throw new NameNotFoundException ();
+
+ ctx = binding.getObject();
+
+ if (ctx instanceof Reference)
+ {
+ //deference the object
+ try
+ {
+ ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env);
+ }
+ catch (NamingException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ __log.warn("",e);
+ throw new NamingException (e.getMessage());
+ }
+ }
+ }
+
+ if (!(ctx instanceof Context))
+ throw new NotContextException();
+
+ return ((Context)ctx).listBindings (cname.getSuffix(1));
+
}
}
+
+ /**
+ *
+ *
+ * @see javax.naming.Context#listBindings(java.lang.String)
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException
+ {
+ synchronized (__root)
+ {
+ return listBindings(__root.getNameParser("").parse(getSuffix(name)));
+ }
+ }
+
+
/**
*
*
diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java
index 0caa18fcefd..d41539de51d 100644
--- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java
+++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java
@@ -12,11 +12,19 @@
// ========================================================================
package org.eclipse.jetty.jndi.java;
+import java.util.Hashtable;
+
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
import org.eclipse.jetty.jndi.NamingUtil;
import org.junit.After;
@@ -31,13 +39,152 @@ import static org.junit.Assert.fail;
*/
public class TestLocalJNDI
{
+ public static class FruitFactory implements ObjectFactory
+ {
+ public FruitFactory()
+ {
+ }
+
+ public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env) throws Exception
+ {
+
+ if (!env.containsKey("flavour"))
+ throw new Exception ("No flavour!");
+
+ if (obj instanceof Reference)
+ {
+ Reference ref = (Reference)obj;
+ if (ref.getClassName().equals(Fruit.class.getName()))
+ {
+ RefAddr addr = ref.get("fruit");
+ if (addr != null)
+ {
+ return new Fruit((String)addr.getContent());
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+
+ public static class Fruit implements Referenceable
+ {
+ String fruit;
+
+ public Fruit(String f)
+ {
+ fruit = f;
+ }
+
+ public Reference getReference() throws NamingException
+ {
+ return new Reference(
+ Fruit.class.getName(),
+ new StringRefAddr("fruit", fruit),
+ FruitFactory.class.getName(),
+ null); // Factory location
+ }
+
+ public String toString()
+ {
+ return fruit;
+ }
+ }
+
+
+
+
+
+
+
+
@After
public void tearDown() throws Exception
{
InitialContext ic = new InitialContext();
ic.destroySubcontext("a");
}
+
+
+ @Test
+ public void testLocalReferenceable() throws Exception
+ {
+ Hashtable env1 = new Hashtable();
+ env1.put("flavour", "orange");
+ InitialContext ic1 = new InitialContext(env1);
+
+ ic1.bind("valencia", new Fruit("orange"));
+
+ Object o = ic1.lookup("valencia");
+ Hashtable env2 = new Hashtable();
+ InitialContext ic2 = new InitialContext(env2);
+ try
+ {
+ o = ic2.lookup("valencia");
+ fail("Constructed object from reference without correct environment");
+ }
+ catch (Exception e)
+ {
+ assertEquals("No flavour!", e.getMessage());
+ }
+ }
+
+
+ @Test
+ public void testLocalEnvironment() throws Exception
+ {
+ Hashtable env1 = new Hashtable();
+ env1.put("make", "holden");
+ env1.put("model", "commodore");
+
+ Object car1 = new Object();
+
+ InitialContext ic = new InitialContext(env1);
+ ic.bind("car1", car1);
+ assertNotNull(ic.lookup("car1"));
+ assertEquals(car1, ic.lookup("car1"));
+
+ Context carz = ic.createSubcontext("carz");
+ assertNotNull(carz);
+ Hashtable ht = carz.getEnvironment();
+ assertNotNull(ht);
+ assertEquals("holden", ht.get("make"));
+ assertEquals("commodore", ht.get("model"));
+
+ Hashtable env2 = new Hashtable();
+ env2.put("flavour", "strawberry");
+ InitialContext ic2 = new InitialContext(env2);
+ assertEquals(car1, ic2.lookup("car1"));
+ Context c = (Context)ic2.lookup("carz");
+ assertNotNull(c);
+ ht = c.getEnvironment();
+ assertEquals("holden", ht.get("make"));
+ assertEquals("commodore", ht.get("model"));
+
+ Context icecreamz = ic2.createSubcontext("icecreamz");
+ ht = icecreamz.getEnvironment();
+ assertNotNull(ht);
+ assertEquals("strawberry", ht.get("flavour"));
+
+ Context hatchbackz = ic2.createSubcontext("carz/hatchbackz");
+ assertNotNull(hatchbackz);
+ ht = hatchbackz.getEnvironment();
+ assertNotNull(ht);
+ assertEquals("holden", ht.get("make"));
+ assertEquals("commodore", ht.get("model"));
+ assertEquals(null, ht.get("flavour"));
+
+ c = (Context)ic.lookup("carz/hatchbackz");
+ assertNotNull(c);
+ assertEquals(hatchbackz, c);
+
+ }
+
+
+
+
@Test
public void testLocal () throws Exception
{
diff --git a/jetty-osgi/jetty-osgi-servletbridge/pom.xml b/jetty-osgi/jetty-osgi-servletbridge/pom.xml
index 156a4a68ac4..703550a8ec6 100644
--- a/jetty-osgi/jetty-osgi-servletbridge/pom.xml
+++ b/jetty-osgi/jetty-osgi-servletbridge/pom.xml
@@ -3,7 +3,7 @@
org.eclipse.jetty.osgi
jetty-osgi-project
- 7.5.1-SNAPSHOT
+ 7.5.2-SNAPSHOT
../pom.xml
4.0.0
@@ -12,6 +12,7 @@
Jetty :: OSGi :: Servletbridge
Jetty OSGi Servletbridge webapp
war
+ false
org.eclipse.equinox
@@ -38,4 +39,15 @@
http://intalio.org/public/maven2
+
+
+
+ org.apache.maven.plugins
+ maven-eclipse-plugin
+
+ false
+
+
+
+
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/BridgeServletExtended.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/BridgeServletExtended.java
new file mode 100644
index 00000000000..4bf16ee2b4d
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/BridgeServletExtended.java
@@ -0,0 +1,48 @@
+// ========================================================================
+// Copyright (c) 2010-2011 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+package org.eclipse.jetty.osgi.servletbridge;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.equinox.servletbridge.BridgeServlet;
+
+/**
+ * Override the BridgeServlet to report on whether equinox is actually started or not
+ * in case it is started asynchroneously.
+ *
+ * @author hmalphettes
+ */
+public class BridgeServletExtended extends BridgeServlet {
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS != null
+ && req.getMethod().equals("GET")) {
+ if (FrameworkLauncherExtended.ASYNCH_START_IN_PROGRESS) {
+ resp.getWriter().append("Equinox is currently starting...\n");
+ return;
+ } else if (FrameworkLauncherExtended.ASYNCH_START_FAILURE != null) {
+ resp.getWriter().append("Equinox failed to start:\n");
+ FrameworkLauncherExtended.ASYNCH_START_FAILURE.printStackTrace(resp.getWriter());
+ return;
+ }
+ }
+ super.service(req, resp);
+ }
+
+}
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java
index 52a926d384b..a0f2021e92f 100644
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java
+++ b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/FrameworkLauncherExtended.java
@@ -49,6 +49,44 @@ public class FrameworkLauncherExtended extends FrameworkLauncher
private boolean deployedInPlace = false;
private URL resourceBaseAsURL = null;
+
+ protected static Boolean ASYNCH_START_IN_PROGRESS;
+ protected static Throwable ASYNCH_START_FAILURE = null;
+
+ /**
+ * If the start is asynch we do it in a different thread and return immediately.
+ */
+ @Override
+ public synchronized void start() {
+ if (ASYNCH_START_IN_PROGRESS == null && "true".equals(super.config.getInitParameter("asyncStart"))) {
+ final ClassLoader webappCl = Thread.currentThread().getContextClassLoader();
+ Thread th = new Thread() {
+ public void run() {
+ Thread.currentThread().setContextClassLoader(webappCl);
+ System.out.println("Jetty-Nested: Starting equinox asynchroneously.");
+ FrameworkLauncherExtended.this.start();
+ System.out.println("Jetty-Nested: Finished starting equinox asynchroneously.");
+ }
+ };
+ ASYNCH_START_IN_PROGRESS = true;
+ try {
+ th.start();
+ } catch (Throwable t) {
+ ASYNCH_START_FAILURE = t;
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException)t;
+ } else {
+ throw new RuntimeException("Equinox failed to start", t);
+ }
+ } finally {
+ ASYNCH_START_IN_PROGRESS = false;
+ }
+ } else {
+ System.out.println("Jetty-Nested: Starting equinox synchroneously.");
+ super.start();
+ System.out.println("Jetty-Nested: Finished starting equinox synchroneously.");
+ }
+ }
/**
* try to find the resource base for this webapp by looking for the launcher initialization file.
@@ -248,7 +286,10 @@ public class FrameworkLauncherExtended extends FrameworkLauncher
String logback = System.getProperty("logback.configurationFile");
if (logback == null)
{
- File etcLogback = new File(jettyHome,"etc/logback.xml");
+ File etcLogback = new File(jettyHome,"etc/logback-nested.xml");
+ if (!etcLogback.exists()) {
+ etcLogback = new File(jettyHome,"etc/logback.xml");
+ }
if (etcLogback.exists())
{
System.setProperty("logback.configurationFile",etcLogback.getAbsolutePath());
diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml b/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml
index c538c7c9bba..c61dee582d1 100644
--- a/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml
+++ b/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml
@@ -5,13 +5,19 @@
proxy
Transparent Proxy Servlet and Equinox Framework Controller
Transparent Proxy Servlet and Equinox Framework Controller
- org.eclipse.equinox.servletbridge.BridgeServlet
+ org.eclipse.jetty.osgi.servletbridge.BridgeServletExtended
+ When this parameter is defined, that equinox installation is launched in place.
+ The parameter can also be passed as a system property. -->
osgi.install.area
/WEB-INF/eclipse
+
+
+
+ asyncStart
+ true
commandline
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java
index 6e2d73f20dd..b869f431b91 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java
@@ -5,9 +5,11 @@ import java.util.IllegalFormatCodePointException;
public abstract class Utf8Appendable
{
+ private final char REPLACEMENT = '\ufffd';
protected final Appendable _appendable;
- protected int _more;
- protected int _bits;
+ protected int _expectedContinuationBytes;
+ protected int _codePoint;
+ protected int _minCodePoint;
public Utf8Appendable(Appendable appendable)
{
@@ -63,91 +65,112 @@ public abstract class Utf8Appendable
protected void appendByte(byte b) throws IOException
{
+ // Check for invalid bytes
+ if (b==(byte)0xc0 || b==(byte)0xc1 || (int)b>=0xf5)
+ {
+ _appendable.append(REPLACEMENT);
+ _expectedContinuationBytes=0;
+ _codePoint=0;
+ throw new NotUtf8Exception();
+ }
+
+ // Is it plain ASCII?
if (b>=0)
{
- if (_more>0)
+ // Were we expecting a continuation byte?
+ if (_expectedContinuationBytes>0)
{
- _appendable.append('?');
- _more=0;
- _bits=0;
+ _appendable.append(REPLACEMENT);
+ _expectedContinuationBytes=0;
+ _codePoint=0;
throw new NotUtf8Exception();
}
else
_appendable.append((char)(0x7f&b));
}
- else if (_more==0)
+ // Else is this a start byte
+ else if (_expectedContinuationBytes==0)
{
- if ((b&0xc0)!=0xc0)
+ if ((b & 0xe0) == 0xc0)
{
- // 10xxxxxx
- _appendable.append('?');
- _more=0;
- _bits=0;
- throw new NotUtf8Exception();
+ //110xxxxx
+ _expectedContinuationBytes=1;
+ _codePoint=b&0x1f;
+ _minCodePoint=0x80;
+ }
+ else if ((b & 0xf0) == 0xe0)
+ {
+ //1110xxxx
+ _expectedContinuationBytes=2;
+ _codePoint=b&0x0f;
+ _minCodePoint=0x800;
+ }
+ else if ((b & 0xf8) == 0xf0)
+ {
+ //11110xxx
+ _expectedContinuationBytes=3;
+ _codePoint=b&0x07;
+ _minCodePoint=0x10000;
+ }
+ else if ((b & 0xfc) == 0xf8)
+ {
+ //111110xx
+ _expectedContinuationBytes=4;
+ _codePoint=b&0x03;
+ _minCodePoint=0x200000;
+ }
+ else if ((b & 0xfe) == 0xfc)
+ {
+ //1111110x
+ _expectedContinuationBytes=5;
+ _codePoint=b&0x01;
+ _minCodePoint=0x400000;
}
else
- {
- if ((b & 0xe0) == 0xc0)
- {
- //110xxxxx
- _more=1;
- _bits=b&0x1f;
- }
- else if ((b & 0xf0) == 0xe0)
- {
- //1110xxxx
- _more=2;
- _bits=b&0x0f;
- }
- else if ((b & 0xf8) == 0xf0)
- {
- //11110xxx
- _more=3;
- _bits=b&0x07;
- }
- else if ((b & 0xfc) == 0xf8)
- {
- //111110xx
- _more=4;
- _bits=b&0x03;
- }
- else if ((b & 0xfe) == 0xfc)
- {
- //1111110x
- _more=5;
- _bits=b&0x01;
- }
- else
- {
- throw new NotUtf8Exception();
- }
+ {
+ _appendable.append(REPLACEMENT);
+ _expectedContinuationBytes=0;
+ _codePoint=0;
+ throw new NotUtf8Exception();
}
}
+ // else is this a continuation character
+ else if ((b&0xc0)==0x80)
+ {
+ // 10xxxxxx
+ _codePoint=(_codePoint<<6)|(b&0x3f);
+
+ // was that the last continuation?
+ if (--_expectedContinuationBytes==0)
+ {
+ // If this a valid unicode point?
+ if (_codePoint<_minCodePoint || (_codePoint>=0xD800 && _codePoint<=0xDFFF))
+ {
+ _appendable.append(REPLACEMENT);
+ _expectedContinuationBytes=0;
+ _codePoint=0;
+ throw new NotUtf8Exception();
+ }
+
+ _minCodePoint=0;
+ char[] chars = Character.toChars(_codePoint);
+ for (char c : chars)
+ _appendable.append(c);
+ }
+ }
+ // Else this is not a continuation character
else
{
- if ((b&0xc0)==0xc0)
- { // 11??????
- _appendable.append('?');
- _more=0;
- _bits=0;
- throw new NotUtf8Exception();
- }
- else
- {
- // 10xxxxxx
- _bits=(_bits<<6)|(b&0x3f);
- if (--_more==0)
- {
- if (_bits>=0xD800 && _bits<=0xDFFF)
- throw new NotUtf8Exception();
- _appendable.append(new String(Character.toChars(_bits)));
- }
- }
+ // ! 10xxxxxx
+ _appendable.append(REPLACEMENT);
+ _expectedContinuationBytes=0;
+ _codePoint=0;
+ throw new NotUtf8Exception();
}
}
- public static class NotUtf8Exception extends IllegalStateException
+ public static class NotUtf8Exception extends IllegalArgumentException
{
public NotUtf8Exception()
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuffer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuffer.java
index 40de5306dce..bd730deabf3 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuffer.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuffer.java
@@ -53,13 +53,13 @@ public class Utf8StringBuffer extends Utf8Appendable
public void reset()
{
_buffer.setLength(0);
- _more=0;
- _bits=0;
+ _expectedContinuationBytes=0;
+ _codePoint=0;
}
public StringBuffer getStringBuffer()
{
- if (_more!=0)
+ if (_expectedContinuationBytes!=0)
throw new NotUtf8Exception();
return _buffer;
}
@@ -67,7 +67,7 @@ public class Utf8StringBuffer extends Utf8Appendable
@Override
public String toString()
{
- if (_more!=0)
+ if (_expectedContinuationBytes!=0)
throw new NotUtf8Exception();
return _buffer.toString();
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuilder.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuilder.java
index 7e4477163c3..541590f6424 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuilder.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8StringBuilder.java
@@ -52,13 +52,13 @@ public class Utf8StringBuilder extends Utf8Appendable
public void reset()
{
_buffer.setLength(0);
- _more=0;
- _bits=0;
+ _expectedContinuationBytes=0;
+ _codePoint=0;
}
public StringBuilder getStringBuilder()
{
- if (_more!=0)
+ if (_expectedContinuationBytes!=0)
throw new NotUtf8Exception();
return _buffer;
}
@@ -66,7 +66,7 @@ public class Utf8StringBuilder extends Utf8Appendable
@Override
public String toString()
{
- if (_more!=0)
+ if (_expectedContinuationBytes!=0)
throw new NotUtf8Exception();
return _buffer.toString();
}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java
index 8a85c295627..a7992b533ec 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java
@@ -7,6 +7,8 @@ import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.util.Scanner.Notification;
import org.junit.AfterClass;
@@ -25,10 +27,8 @@ public class ScannerTest
@BeforeClass
public static void setUpBeforeClass() throws Exception
{
- _directory = File.createTempFile("scan","");
- _directory.delete();
- _directory.mkdir();
- _directory.deleteOnExit();
+ _directory = MavenTestingUtils.getTargetTestingDir(ScannerTest.class.getSimpleName());
+ FS.ensureEmpty(_directory);
_scanner = new Scanner();
_scanner.addScanDir(_directory);
@@ -88,7 +88,7 @@ public class ScannerTest
public void testAddedChangeRemove() throws Exception
{
// TODO needs to be further investigated
- Assume.assumeTrue(!OS.IS_WINDOWS && !OS.IS_OSX);
+ Assume.assumeTrue(!OS.IS_WINDOWS);
touch("a0");
@@ -96,7 +96,7 @@ public class ScannerTest
_scanner.scan();
_scanner.scan();
Event event = _queue.poll();
- Assert.assertTrue(event!=null);
+ Assert.assertNotNull("Event should not be null", event);
Assert.assertEquals(_directory+"/a0",event._filename);
Assert.assertEquals(Notification.ADDED,event._notification);
@@ -197,7 +197,7 @@ public class ScannerTest
public void testSizeChange() throws Exception
{
// TODO needs to be further investigated
- Assume.assumeTrue(!OS.IS_WINDOWS && !OS.IS_OSX);
+ Assume.assumeTrue(!OS.IS_WINDOWS);
touch("tsc0");
_scanner.scan();
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java
index 5b0c3afae54..9c44625e8fe 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java
@@ -48,9 +48,9 @@ public class Utf8StringBufferTest
buffer.toString();
assertTrue(false);
}
- catch(IllegalStateException e)
+ catch(Utf8Appendable.NotUtf8Exception e)
{
- assertTrue(e.toString().indexOf("!UTF-8")>=0);
+ assertTrue(true);
}
}
@@ -70,11 +70,11 @@ public class Utf8StringBufferTest
buffer.append(bytes[i]);
assertTrue(false);
}
- catch(IllegalStateException e)
+ catch(Utf8Appendable.NotUtf8Exception e)
{
assertTrue(e.toString().indexOf("!UTF-8")>=0);
}
- assertEquals("abc?",buffer.toString());
+ assertEquals("abc\ufffd",buffer.toString());
}
@Test
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java
index 9cfca551290..bfa0cccd870 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java
@@ -25,19 +25,44 @@ public class Utf8StringBuilderTest
public void testInvalid()
throws Exception
{
- Utf8StringBuilder buffer = new Utf8StringBuilder();
- buffer.append((byte)0xED);
- buffer.append((byte)0xA0);
- try
- {
- buffer.append((byte)0x80);
- assertTrue(false);
- }
- catch(Utf8Appendable.NotUtf8Exception e)
- {
- assertTrue(true);
- }
+ String[] invalids = {
+ "c0af",
+ "EDA080",
+ "f08080af",
+ "f8808080af",
+ "e080af",
+ "F4908080",
+ "fbbfbfbfbf"
+ };
+ for (String i : invalids)
+ {
+ byte[] bytes = TypeUtil.fromHexString(i);
+
+ /* Test what JVM does
+ try
+ {
+ String s = new String(bytes,0,bytes.length,"UTF-8");
+ System.err.println(i+": "+s);
+ }
+ catch(Exception e)
+ {
+ System.err.println(i+": "+e);
+ }
+ */
+
+ try
+ {
+ Utf8StringBuilder buffer = new Utf8StringBuilder();
+ buffer.append(bytes,0,bytes.length);
+
+ assertEquals(i,"not expected",buffer.toString());
+ }
+ catch(IllegalArgumentException e)
+ {
+ assertTrue(i,true);
+ }
+ }
}
@Test
@@ -69,7 +94,7 @@ public class Utf8StringBuilderTest
buffer.toString();
assertTrue(false);
}
- catch(IllegalStateException e)
+ catch(Utf8Appendable.NotUtf8Exception e)
{
assertTrue(e.toString().indexOf("!UTF-8")>=0);
}
@@ -91,11 +116,11 @@ public class Utf8StringBuilderTest
buffer.append(bytes[i]);
assertTrue(false);
}
- catch(IllegalStateException e)
+ catch(Utf8Appendable.NotUtf8Exception e)
{
- assertTrue(e.toString().indexOf("!UTF-8")>=0);
+ assertTrue(true);
}
- assertEquals("abc?", buffer.toString());
+ assertEquals("abc\ufffd", buffer.toString());
}
@@ -106,6 +131,7 @@ public class Utf8StringBuilderTest
String source="\uD842\uDF9F";
byte[] bytes=source.getBytes("UTF-8");
+ // System.err.println(TypeUtil.toHexString(bytes));
String jvmcheck = new String(bytes,0,bytes.length,"UTF-8");
assertEquals(source,jvmcheck);
diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java
index bcda94485a8..813b64220eb 100644
--- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java
+++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnectionD13.java
@@ -30,6 +30,7 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8Appendable;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.log.Log;
@@ -627,7 +628,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
public void onFrame(final byte flags, final byte opcode, final Buffer buffer)
{
boolean lastFrame = isLastFrame(flags);
-
+
synchronized(WebSocketConnectionD13.this)
{
// Ignore incoming after a close
@@ -827,19 +828,21 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
return;
}
}
+ catch(ThreadDeath th)
+ {
+ throw th;
+ }
catch(Utf8Appendable.NotUtf8Exception notUtf8)
{
LOG.warn("{} for {}",notUtf8,_endp);
LOG.debug(notUtf8);
errorClose(WebSocketConnectionD13.CLOSE_BAD_PAYLOAD,"Invalid UTF-8");
}
- catch(ThreadDeath th)
+ catch(Throwable probablyNotUtf8)
{
- throw th;
- }
- catch(Throwable th)
- {
- LOG.warn(th);
+ LOG.warn("{} for {}",probablyNotUtf8,_endp);
+ LOG.debug(probablyNotUtf8);
+ errorClose(WebSocketConnectionD13.CLOSE_BAD_PAYLOAD,"Invalid Payload: "+probablyNotUtf8);
}
}
diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestClient.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestClient.java
index 80716955347..8a29da81323 100644
--- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestClient.java
+++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestClient.java
@@ -52,6 +52,8 @@ public class TestClient implements WebSocket.OnFrame
public void onOpen(Connection connection)
{
+ if (_verbose)
+ System.err.printf("%s#onHandshake %s %s\n",this.getClass().getSimpleName(),connection,connection.getClass().getSimpleName());
}
public void onClose(int closeCode, String message)
@@ -141,7 +143,7 @@ public class TestClient implements WebSocket.OnFrame
byte op=(byte)(off==0?opcode:WebSocketConnectionD13.OP_CONTINUATION);
if (_verbose)
- System.err.printf("%s#addFrame %s|%s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(flags),TypeUtil.toHexString(op),TypeUtil.toHexString(data,off,len));
+ System.err.printf("%s#sendFrame %s|%s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(flags),TypeUtil.toHexString(op),TypeUtil.toHexString(data,off,len));
_connection.sendFrame(flags,op,data,off,len);
@@ -168,6 +170,7 @@ public class TestClient implements WebSocket.OnFrame
System.err.println(" -p|--port PORT (default 8080)");
System.err.println(" -b|--binary");
System.err.println(" -v|--verbose");
+ System.err.println(" -q|--quiet");
System.err.println(" -c|--count n (default 10)");
System.err.println(" -s|--size n (default 64)");
System.err.println(" -f|--fragment n (default 4000) ");
@@ -226,6 +229,8 @@ public class TestClient implements WebSocket.OnFrame
try
{
__start=System.currentTimeMillis();
+ protocol=protocol==null?"echo":protocol;
+
for (int i=0;i1?"s":"")+" ---");
- System.out.println(__framesSent+" frames transmitted, "+__framesReceived+" received, "+
- __messagesSent+" messages transmitted, "+__messagesReceived+" received, "+
- "time "+duration+"ms "+ (1000L*__messagesReceived.get()/duration)+" req/s");
+ System.out.printf("%d/%d frames sent/recv, %d/%d mesg sent/recv, time %dms %dm/s %.2fbps%n",
+ __framesSent,__framesReceived.get(),
+ __messagesSent,__messagesReceived.get(),
+ duration,(1000L*__messagesReceived.get()/duration),
+ 1000.0D*__messagesReceived.get()*8*size/duration/1024/1024);
System.out.printf("rtt min/ave/max = %.3f/%.3f/%.3f ms\n",__minDuration.get()/1000000.0,__messagesReceived.get()==0?0.0:(__totalTime.get()/__messagesReceived.get()/1000000.0),__maxDuration.get()/1000000.0);
__clientFactory.stop();
diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestServer.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestServer.java
index ab9743392e2..ebdd1a0d8be 100644
--- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestServer.java
+++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestServer.java
@@ -107,7 +107,7 @@ public class TestServer extends Server
public void onOpen(Connection connection)
{
if (_verbose)
- System.err.printf("%s#onOpen %s\n",this.getClass().getSimpleName(),connection);
+ System.err.printf("%s#onOpen %s %s\n",this.getClass().getSimpleName(),connection,connection.getProtocol());
}
public void onHandshake(FrameConnection connection)
diff --git a/pom.xml b/pom.xml
index 8f0256af067..fcb8e146e5c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
org.eclipse.jetty
jetty-parent
- 18
+ 19-SNAPSHOT
org.eclipse.jetty
jetty-project
diff --git a/test-jetty-webapp/src/main/java/com/acme/TestFilter.java b/test-jetty-webapp/src/main/java/com/acme/TestFilter.java
index 3712a2c7db4..18758dd276c 100644
--- a/test-jetty-webapp/src/main/java/com/acme/TestFilter.java
+++ b/test-jetty-webapp/src/main/java/com/acme/TestFilter.java
@@ -73,7 +73,7 @@ public class TestFilter implements Filter
String to = request.getServerName();
String path=((HttpServletRequest)request).getServletPath();
- if (!_remote && !_allowed.contains(path) && (
+ if (!"/remote.html".equals(path) && !_remote && !_allowed.contains(path) && (
!from.equals("localhost") && !from.startsWith("127.") && from.indexOf(":1")<0 ||
!to.equals("localhost")&&!to.startsWith("127.0.0.") && to.indexOf(":1")<0))
{