diff --git a/.gitignore b/.gitignore index 56b34575555..11c793e1afe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,33 @@ -target/ +# eclipse .classpath .project .settings + +# maven +target/ */src/main/java/META-INF/ -.pmd + +# common junk *.log *.swp *.diff *.patch + +# intellij *.iml *.ipr *.iws .idea/ + +# Mac filesystem dust +/.DS_Store + +# pmd +.pmdruleset +.pmd + +# netbeans +/nbproject + +# vim +.*.sw[a-p] diff --git a/jetty-aggregate/jetty-all-server/pom.xml b/jetty-aggregate/jetty-all-server/pom.xml index 7e6c16a86e8..ec94c3d2af1 100644 --- a/jetty-aggregate/jetty-all-server/pom.xml +++ b/jetty-aggregate/jetty-all-server/pom.xml @@ -5,7 +5,6 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-all-server Jetty :: Aggregate :: All Server diff --git a/jetty-aggregate/jetty-all/pom.xml b/jetty-aggregate/jetty-all/pom.xml index be1cfab7da2..c65e5c899af 100644 --- a/jetty-aggregate/jetty-all/pom.xml +++ b/jetty-aggregate/jetty-all/pom.xml @@ -5,10 +5,8 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-all Jetty :: Aggregate :: All core Jetty - ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-client/pom.xml b/jetty-aggregate/jetty-client/pom.xml index aa987775861..31ef23da330 100644 --- a/jetty-aggregate/jetty-client/pom.xml +++ b/jetty-aggregate/jetty-client/pom.xml @@ -5,7 +5,6 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-client Jetty :: Aggregate :: HTTP Client diff --git a/jetty-aggregate/jetty-plus/pom.xml b/jetty-aggregate/jetty-plus/pom.xml index b42b44a4725..4ae4e9bf450 100644 --- a/jetty-aggregate/jetty-plus/pom.xml +++ b/jetty-aggregate/jetty-plus/pom.xml @@ -5,7 +5,6 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-plus Jetty :: Aggregate :: Plus Server diff --git a/jetty-aggregate/jetty-server/pom.xml b/jetty-aggregate/jetty-server/pom.xml index bf5c6d4fb02..92c03bc43bb 100644 --- a/jetty-aggregate/jetty-server/pom.xml +++ b/jetty-aggregate/jetty-server/pom.xml @@ -5,7 +5,6 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-server Jetty :: Aggregate :: HTTP Server diff --git a/jetty-aggregate/jetty-servlet/pom.xml b/jetty-aggregate/jetty-servlet/pom.xml index 066c8733d8b..9f40904f08a 100644 --- a/jetty-aggregate/jetty-servlet/pom.xml +++ b/jetty-aggregate/jetty-servlet/pom.xml @@ -5,7 +5,6 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-servlet Jetty :: Aggregate :: Servlet Server diff --git a/jetty-aggregate/jetty-webapp/pom.xml b/jetty-aggregate/jetty-webapp/pom.xml index 9413b7d44df..9db6c5896fa 100644 --- a/jetty-aggregate/jetty-webapp/pom.xml +++ b/jetty-aggregate/jetty-webapp/pom.xml @@ -5,7 +5,6 @@ 7.5.2-SNAPSHOT 4.0.0 - org.eclipse.jetty.aggregate jetty-webapp Jetty :: Aggregate :: WebApp Server diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java index 5b80a68d9df..2a01ba3d2a4 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java @@ -4,11 +4,11 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io.nio; @@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import org.eclipse.jetty.io.ConnectedEndPoint; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; @@ -55,7 +54,7 @@ import org.eclipse.jetty.util.thread.Timeout.Task; public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable { public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio"); - + // TODO Tune these by approx system speed. private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD",0).intValue(); private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue(); @@ -63,7 +62,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue(); private static final int __BUSY_KEY=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_KEY",-1).intValue(); private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue(); - + private int _maxIdleTime; private int _lowResourcesMaxIdleTime; private long _lowResourcesConnections; @@ -72,7 +71,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa private volatile int _set; private boolean _deferringInterestedOps0=true; private int _selectorPriorityDelta=0; - + /* ------------------------------------------------------------ */ /** * @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed. @@ -82,18 +81,18 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { _maxIdleTime=(int)maxIdleTime; } - + /* ------------------------------------------------------------ */ /** * @param selectSets number of select sets to create */ public void setSelectSets(int selectSets) { - long lrc = _lowResourcesConnections * _selectSets; + long lrc = _lowResourcesConnections * _selectSets; _selectSets=selectSets; _lowResourcesConnections=lrc/_selectSets; } - + /* ------------------------------------------------------------ */ /** * @return the max idle time @@ -102,7 +101,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { return _maxIdleTime; } - + /* ------------------------------------------------------------ */ /** * @return the number of select sets in use @@ -114,14 +113,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa /* ------------------------------------------------------------ */ /** - * @param i + * @param i * @return The select set */ public SelectSet getSelectSet(int i) { return _selectSet[i]; } - + /* ------------------------------------------------------------ */ /** Register a channel * @param channel @@ -132,8 +131,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa // The ++ increment here is not atomic, but it does not matter. // so long as the value changes sometimes, then connections will // be distributed over the available sets. - - int s=_set++; + + int s=_set++; s=s%_selectSets; SelectSet[] sets=_selectSet; if (sets!=null) @@ -144,7 +143,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } } - + /* ------------------------------------------------------------ */ /** Register a channel * @param channel @@ -154,8 +153,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa // The ++ increment here is not atomic, but it does not matter. // so long as the value changes sometimes, then connections will // be distributed over the available sets. - - int s=_set++; + + int s=_set++; s=s%_selectSets; SelectSet[] sets=_selectSet; if (sets!=null) @@ -165,14 +164,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa set.wakeup(); } } - + /* ------------------------------------------------------------ */ /** Register a {@link ServerSocketChannel} * @param acceptChannel */ public void register(ServerSocketChannel acceptChannel) { - int s=_set++; + int s=_set++; s=s%_selectSets; SelectSet set=_selectSet[s]; set.addChange(acceptChannel); @@ -196,8 +195,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { _selectorPriorityDelta=delta; } - - + + /* ------------------------------------------------------------ */ /** * @return the lowResourcesConnections @@ -237,7 +236,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { _lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime; } - + /* ------------------------------------------------------------------------------- */ public abstract boolean dispatch(Runnable task); @@ -254,7 +253,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _selectSet[i]= new SelectSet(i); super.doStart(); - + // start a thread to Select for (int i=0;i _changes = new ConcurrentLinkedQueue(); - + private volatile Selector _selector; - + private volatile Thread _selecting; private int _jvmBug; private int _selects; @@ -404,7 +403,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa private int _jvmFix2; private volatile long _idleTick; private ConcurrentMap _endPoints = new ConcurrentHashMap(); - + /* ------------------------------------------------------------ */ SelectSet(int acceptorID) throws Exception { @@ -420,7 +419,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _monitorNext=_monitorStart+__MONITOR_PERIOD; _log=_monitorStart+60000; } - + /* ------------------------------------------------------------ */ public void addChange(Object change) { @@ -429,7 +428,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa /* ------------------------------------------------------------ */ public void addChange(SelectableChannel channel, Object att) - { + { if (att==null) addChange(channel); else if (att instanceof EndPoint) @@ -437,11 +436,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa else addChange(new ChannelAndAttachment(channel,att)); } - + /* ------------------------------------------------------------ */ /** * Select and dispatch tasks found from changes and the selector. - * + * * @throws IOException */ public void doSelect() throws IOException @@ -450,6 +449,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { _selecting=Thread.currentThread(); final Selector selector=_selector; + // Stopped concurrently ? + if (selector == null) + return; // Make any key changes required Object change; @@ -458,7 +460,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { Channel ch=null; SelectionKey key=null; - + try { if (change instanceof EndPoint) @@ -475,7 +477,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa final SelectableChannel channel=asc._channel; ch=channel; final Object att = asc._attachment; - + if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected()) { key = channel.register(selector,SelectionKey.OP_READ,att); @@ -517,7 +519,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { if (e instanceof ThreadDeath) throw (ThreadDeath)e; - + if (isRunning()) LOG.warn(e); else @@ -540,7 +542,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _selects++; long now=System.currentTimeMillis(); - + // if no immediate things to do if (selected==0 && selector.selectedKeys().isEmpty()) { @@ -562,7 +564,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _timeout.setNow(now); long to_next_timeout=_timeout.getTimeToNext(); - long wait = _changes.size()==0?__IDLE_TICK:0L; + long wait = _changes.size()==0?__IDLE_TICK:0L; if (wait > 0 && to_next_timeout >= 0 && wait > to_next_timeout) wait = to_next_timeout; @@ -574,21 +576,21 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _selects++; now = System.currentTimeMillis(); _timeout.setNow(now); - + if (__JVMBUG_THRESHHOLD>0) checkJvmBugs(before, now, wait, selected); } } - + // have we been destroyed while sleeping if (_selector==null || !selector.isOpen()) return; // Look for things to do for (SelectionKey key: selector.selectedKeys()) - { + { SocketChannel channel=null; - + try { if (!key.isValid()) @@ -641,7 +643,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa SelectChannelEndPoint endpoint = createEndPoint(channel,key); key.attach(endpoint); if (key.isReadable()) - endpoint.schedule(); + endpoint.schedule(); } key = null; } @@ -665,15 +667,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { LOG.debug(e2); } - + if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid()) key.cancel(); } } - + // Everything always handled selector.selectedKeys().clear(); - + now=System.currentTimeMillis(); _timeout.setNow(now); Task task = _timeout.expired(); @@ -688,11 +690,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa if (now-_idleTick>__IDLE_TICK) { _idleTick=now; - + final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections)) ?(now+_maxIdleTime-_lowResourcesMaxIdleTime) :now; - + dispatch(new Runnable() { public void run() @@ -721,7 +723,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _selecting=null; } } - + /* ------------------------------------------------------------ */ private void checkJvmBugs(long before, long now, long wait, int selected) throws IOException @@ -729,7 +731,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa Selector selector = _selector; if (selector==null) return; - + // Look for JVM bugs over a monitor period. // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933 // http://bugs.sun.com/view_bug.do?bug_id=6693490 @@ -748,7 +750,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa if (now>_log) { - if (_paused>0) + if (_paused>0) LOG.debug(this+" Busy selector - injecting delay "+_paused+" times"); if (_jvmFix2>0) @@ -842,9 +844,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa _busyKey=busy; } } - + /* ------------------------------------------------------------ */ - private void renewSelector() + private void renewSelector() { try { @@ -876,7 +878,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa throw new RuntimeException("recreating selector",e); } } - + /* ------------------------------------------------------------ */ public SelectorManager getManager() { @@ -891,9 +893,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa /* ------------------------------------------------------------ */ /** - * @param task The task to timeout. If it implements Runnable, then + * @param task The task to timeout. If it implements Runnable, then * expired will be called from a dispatched thread. - * + * * @param timeoutMs */ public void scheduleTimeout(Timeout.Task task, long timeoutMs) @@ -902,7 +904,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa throw new IllegalArgumentException("!Runnable"); _timeout.schedule(task, timeoutMs); } - + /* ------------------------------------------------------------ */ public void cancelTimeout(Timeout.Task task) { @@ -927,20 +929,20 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa renewSelector(); } }); - + renewSelector(); } } - + /* ------------------------------------------------------------ */ private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException { SelectChannelEndPoint endp = newEndPoint(channel,this,sKey); - endPointOpened(endp); + endPointOpened(endp); _endPoints.put(endp,this); return endp; } - + /* ------------------------------------------------------------ */ public void destroyEndPoint(SelectChannelEndPoint endp) { @@ -953,11 +955,11 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { return _selector; } - + /* ------------------------------------------------------------ */ void stop() throws Exception { - // Spin for a while waiting for selector to complete + // Spin for a while waiting for selector to complete // to avoid unneccessary closed channel exceptions try { @@ -994,8 +996,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa } } } - - + + _timeout.cancelAll(); try { @@ -1006,7 +1008,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa catch (IOException e) { LOG.ignore(e); - } + } _selector=null; } } @@ -1021,9 +1023,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa public void dump(Appendable out, String indent) throws IOException { out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_setID)).append("\n"); - + Thread selecting = _selecting; - + Object where = "not selecting"; StackTraceElement[] trace =selecting==null?null:selecting.getStackTrace(); if (trace!=null) @@ -1039,9 +1041,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa Selector selector=_selector; final ArrayList dump = new ArrayList(selector.keys().size()*2); dump.add(where); - + final CountDownLatch latch = new CountDownLatch(1); - + addChange(new Runnable(){ public void run() { @@ -1049,7 +1051,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa latch.countDown(); } }); - + try { latch.await(5,TimeUnit.SECONDS); @@ -1081,7 +1083,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { final SelectableChannel _channel; final Object _attachment; - + public ChannelAndAttachment(SelectableChannel channel, Object attachment) { super(); @@ -1101,12 +1103,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa { _deferringInterestedOps0 = deferringInterestedOps0; } - + /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ private interface ChangeTask extends Runnable {} - + } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java new file mode 100644 index 00000000000..14a2b8fe35d --- /dev/null +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java @@ -0,0 +1,69 @@ +// ======================================================================== +// Copyright (c) 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.jndi; + +import java.util.Iterator; + +import javax.naming.Binding; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** BindingEnumeration + *

Implementation of NamingEnumeration + * + *

Notes

+ *

Used to return results of Context.listBindings(); + * + *

Usage

+ * + */ +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); + } +} \ No newline at end of file diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java new file mode 100644 index 00000000000..432fa65f3df --- /dev/null +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java @@ -0,0 +1,69 @@ +// ======================================================================== +// Copyright (c) 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.jndi; + +import java.util.Iterator; + +import javax.naming.Binding; +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** NameEnumeration + *

Implementation of NamingEnumeration interface. + * + *

Notes

+ *

Used for returning results of Context.list(); + * + *

Usage

+ * + */ +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); + } +} \ 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)) {