JBoss Cache SVN: r5337 - core/trunk/src/main/java/org/jboss/cache/marshall.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-02-08 13:24:39 -0500 (Fri, 08 Feb 2008)
New Revision: 5337
Modified:
core/trunk/src/main/java/org/jboss/cache/marshall/VersionAwareMarshaller.java
Log:
push back header if it doesn't exist in the stream
Modified: core/trunk/src/main/java/org/jboss/cache/marshall/VersionAwareMarshaller.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/VersionAwareMarshaller.java 2008-02-08 15:58:29 UTC (rev 5336)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/VersionAwareMarshaller.java 2008-02-08 18:24:39 UTC (rev 5337)
@@ -13,6 +13,7 @@
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.marshall.io.ObjectStreamPool;
+import org.jboss.cache.marshall.io.ReusableObjectInputStream;
import org.jboss.cache.marshall.io.ReusableObjectOutputStream;
import org.jboss.cache.util.Util;
import org.jboss.util.stream.MarshalledValueInputStream;
@@ -22,6 +23,8 @@
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.PushbackInputStream;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
@@ -237,7 +240,16 @@
// we don't have a reusable implementation for non-byte-backed streams as yet.
short versionId;
Marshaller marshaller;
- ObjectInputStream in = new MarshalledValueInputStream(is);
+ PushbackInputStream pis = new PushbackInputStream(is);
+ byte[] first4bytes = new byte[4];
+ pis.read(first4bytes);
+ boolean needToWriteHeader = !Arrays.equals(first4bytes, ReusableObjectInputStream.INIT_BYTES);
+ // first push back the bytes read
+ pis.unread(first4bytes);
+ if (needToWriteHeader) pis.unread(ReusableObjectInputStream.INIT_BYTES);
+
+ ObjectInputStream in = new MarshalledValueInputStream(pis);
+
try
{
versionId = in.readShort();
17 years, 8 months
JBoss Cache SVN: r5336 - core/trunk/src/main/java/org/jboss/cache/config.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-02-08 10:58:29 -0500 (Fri, 08 Feb 2008)
New Revision: 5336
Modified:
core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java
Log:
allow cfg changes when cache status is STARTING
Modified: core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java 2008-02-08 13:45:23 UTC (rev 5335)
+++ core/trunk/src/main/java/org/jboss/cache/config/ConfigurationComponent.java 2008-02-08 15:58:29 UTC (rev 5336)
@@ -105,7 +105,7 @@
{
try
{
- if (!accessible && cache != null && cache.getCacheStatus() != null && (cache.getCacheStatus() == CacheStatus.STARTED || cache.getCacheStatus() == CacheStatus.STARTING) && !getClass().getDeclaredField(fieldName).isAnnotationPresent(Dynamic.class))
+ if (!accessible && cache != null && cache.getCacheStatus() != null && cache.getCacheStatus() == CacheStatus.STARTED && !getClass().getDeclaredField(fieldName).isAnnotationPresent(Dynamic.class))
{
throw new ConfigurationException("Attempted to modify a non-Dynamic configuration element [" + fieldName + "] after the cache has started!");
}
17 years, 8 months
JBoss Cache SVN: r5335 - core/trunk/src/main/java/org/jboss/cache/factories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-02-08 08:45:23 -0500 (Fri, 08 Feb 2008)
New Revision: 5335
Modified:
core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
Log:
Should always name components based on expected type, not instance class since this can be a proxy or a subclass or implementation that dependent components don't know about.
Modified: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-02-08 13:34:16 UTC (rev 5334)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-02-08 13:45:23 UTC (rev 5335)
@@ -137,7 +137,7 @@
*/
public void registerComponent(Object component, Class type)
{
- registerComponent(component.getClass().getName(), component, type);
+ registerComponent(type.getName(), component, type);
}
/**
17 years, 8 months
JBoss Cache SVN: r5334 - core/trunk/src/test/resources.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-02-08 08:34:16 -0500 (Fri, 08 Feb 2008)
New Revision: 5334
Modified:
core/trunk/src/test/resources/log4j.xml
Log:
Official version of the log4j.xml file for distribution
Modified: core/trunk/src/test/resources/log4j.xml
===================================================================
--- core/trunk/src/test/resources/log4j.xml 2008-02-08 13:30:51 UTC (rev 5333)
+++ core/trunk/src/test/resources/log4j.xml 2008-02-08 13:34:16 UTC (rev 5334)
@@ -22,7 +22,7 @@
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
- <param name="File" value="output/jbosscache.log"/>
+ <param name="File" value="jbosscache.log"/>
<param name="Append" value="true"/>
<!-- Rollover at midnight each day -->
@@ -31,7 +31,7 @@
<!-- Rollover at the top of each hour
<param name="DatePattern" value="'.'yyyy-MM-dd-HH"/>
-->
- <param name="Threshold" value="DEBUG"/>
+ <param name="Threshold" value="TRACE"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
@@ -66,6 +66,10 @@
<priority value="WARN"/>
</category>
+ <category name="org.jboss.cache.factories">
+ <priority value="ERROR"/>
+ </category>
+
<category name="org.jboss.tm">
<priority value="WARN"/>
</category>
17 years, 8 months
JBoss Cache SVN: r5333 - in core/trunk/src: main/java/org/jboss/cache/factories and 3 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-02-08 08:30:51 -0500 (Fri, 08 Feb 2008)
New Revision: 5333
Added:
core/trunk/src/main/java/org/jboss/cache/factories/annotations/CacheInjectionMethods.java
core/trunk/src/main/java/org/jboss/cache/util/reflect/CachedMethod.java
Modified:
core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
core/trunk/src/test/java/org/jboss/cache/api/NodeAPITest.java
core/trunk/src/test/java/org/jboss/cache/api/NodeSPITest.java
Log:
Performance enhancements
Modified: core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeSPI.java 2008-02-08 09:32:51 UTC (rev 5332)
+++ core/trunk/src/main/java/org/jboss/cache/NodeSPI.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -40,6 +40,11 @@
* It is important to node that the direct <b>read</b> methods, such as getDataDirect(), return unmodifiable collections.
* In addition to being unmodifiable, they are also defensively copied from the underlying data map to ensure view consistency.
* <p/>
+ * <b>Note:</b> the above paragraph was true for JBoss Cache 2.0.0, but for 2.1.0, this has changed to now offer direct view of
+ * the data structures, since the defensive copying was seriously affecting scalability. Please use the *Direct() methods
+ * with care - even though you may be able to directly manipulate the data structures returned, the cache isn't designed
+ * for you to do so. Use with care.
+ * <p/>
*
* @author <a href="mailto:manik@jboss.org">Manik Surtani (manik(a)jboss.org)</a>
* @see Node
Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-02-08 09:32:51 UTC (rev 5332)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -8,6 +8,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.factories.annotations.CacheInjectionMethods;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.lock.IdentityLock;
import org.jboss.cache.marshall.MarshalledValue;
@@ -32,6 +33,7 @@
* @since 2.0.0
*/
@SuppressWarnings("unchecked")
+@CacheInjectionMethods
public class UnversionedNode<K, V> extends AbstractNode<K, V>
{
/**
@@ -221,7 +223,8 @@
public Map getDataDirect()
{
if (data == null) return Collections.emptyMap();
- return Collections.unmodifiableMap(data);
+ //return Collections.unmodifiableMap(data);
+ return data; // wrapping in an unmodifiable map is too expensive!
}
public Object put(Object key, Object value)
@@ -484,7 +487,8 @@
public Set<Object> getChildrenNamesDirect()
{
- return children == null ? Collections.emptySet() : new HashSet<Object>(children.keySet());
+ //return children == null ? Collections.emptySet() : new HashSet<Object>(children.keySet());
+ return children == null ? Collections.emptySet() : children.keySet();
}
public Set<Object> getKeysDirect()
@@ -493,7 +497,8 @@
{
return Collections.emptySet();
}
- return Collections.unmodifiableSet(new HashSet<Object>(data.keySet()));
+// return Collections.unmodifiableSet(new HashSet<Object>(data.keySet()));
+ return data.keySet();
}
public boolean removeChildDirect(Object childName)
@@ -632,7 +637,8 @@
NodeSPI spi = (NodeSPI) n;
if (!spi.isDeleted()) exclDeleted.add(spi);
}
- return Collections.unmodifiableSet(exclDeleted);
+// return Collections.unmodifiableSet(exclDeleted);
+ return exclDeleted;
}
public boolean hasChildrenDirect()
@@ -646,7 +652,8 @@
{
if (children != null && !children.isEmpty())
{
- return Collections.unmodifiableSet(new HashSet(children.values()));
+// return Collections.unmodifiableSet(new HashSet(children.values()));
+ return new HashSet(children.values());
}
else
{
Modified: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-02-08 09:32:51 UTC (rev 5332)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -9,6 +9,7 @@
import org.jboss.cache.config.ConfigurationException;
import org.jboss.cache.config.RuntimeConfig;
import static org.jboss.cache.factories.ComponentRegistry.State.*;
+import org.jboss.cache.factories.annotations.CacheInjectionMethods;
import org.jboss.cache.factories.annotations.ComponentName;
import org.jboss.cache.factories.annotations.DefaultFactoryFor;
import org.jboss.cache.factories.annotations.Inject;
@@ -16,6 +17,7 @@
import org.jboss.cache.factories.annotations.Stop;
import org.jboss.cache.invocation.RemoteCacheInvocationDelegate;
import org.jboss.cache.util.BeanUtils;
+import org.jboss.cache.util.reflect.CachedMethod;
import org.jboss.cache.util.reflect.ReflectionUtil;
import java.lang.annotation.Annotation;
@@ -76,6 +78,11 @@
private static Log log = LogFactory.getLog(ComponentRegistry.class);
private Bootstrap bootstrap;
+ // cache of reflection methods to call during injections. These will be emptied when start() is called.
+ Map<Class, List<CachedMethod>> shortTermMethodCache = null;
+ // these will hang around longer - for components that are frequently created during normal operation.
+ Map<Class, List<CachedMethod>> longTermMethodCache = null;
+
/**
* Creates an instance of the component registry. The configuration passed in is automatically registered.
*
@@ -425,11 +432,12 @@
//if (log.isTraceEnabled()) log.trace("Inspecting class " + target.getClass());
try
{
- List<Method> methods = ReflectionUtil.getAllMethods(target.getClass(), Inject.class);
+ // look in caches first
+ List<CachedMethod> methods = lookupInjectionMethods(target.getClass());
//if (log.isTraceEnabled()) log.trace("Found method set containing " + methods.size() + " methods that need injection: " + methods);
// search for anything we need to inject
- for (Method method : methods)
+ for (CachedMethod method : methods)
{
//if (log.isTraceEnabled()) log.trace("Method " + method + " needs some other components injected!");
performInjection(method, target);
@@ -441,6 +449,26 @@
}
}
+ private List<CachedMethod> lookupInjectionMethods(Class type)
+ {
+ if (longTermMethodCache != null && longTermMethodCache.containsKey(type)) return longTermMethodCache.get(type);
+ if (shortTermMethodCache != null && shortTermMethodCache.containsKey(type)) return shortTermMethodCache.get(type);
+
+ List<CachedMethod> methods = ReflectionUtil.getAllCachedMethods(type, Inject.class);
+ if (type.isAnnotationPresent(CacheInjectionMethods.class))
+ {
+ if (longTermMethodCache == null) longTermMethodCache = new HashMap<Class, List<CachedMethod>>();
+ longTermMethodCache.put(type, methods);
+ }
+ else
+ {
+ if (shortTermMethodCache == null) shortTermMethodCache = new HashMap<Class, List<CachedMethod>>();
+ shortTermMethodCache.put(type, methods);
+ }
+
+ return methods;
+ }
+
/**
* Looks through the parameter list of the given method, attempts to locate parameters that fit the types that may
* exist in the {@link ComponentRegistry}, and then calls the method on the target object with the necessary parameters.
@@ -452,7 +480,7 @@
* if the method cannot be called
*/
@SuppressWarnings("unchecked")
- private <T> void performInjection(Method method, T target) throws IllegalAccessException, InvocationTargetException
+ private <T> void performInjection(CachedMethod method, T target) throws IllegalAccessException, InvocationTargetException
{
Class[] parameterTypes = method.getParameterTypes();
List<Component> componentsToInject = getDeclaredDependencies(method);
@@ -464,12 +492,13 @@
parameters[i] = getComponent(componentsToInject.get(i).name, parameterTypes[i]);
}
+ Method reflectMethod = method.getMethod();
// make sure we set this method to be accessible, so we can call private, package and protected
// methods rather than just public ones.
- method.setAccessible(true);
+ reflectMethod.setAccessible(true);
// invoke the method with the parameters we've worked out.
- method.invoke(target, parameters);
+ reflectMethod.invoke(target, parameters);
}
private String extractComponentName(Annotation[] annotationsOnParameter)
@@ -485,7 +514,7 @@
return null;
}
- private List<Component> getDeclaredDependencies(Method method)
+ private List<Component> getDeclaredDependencies(CachedMethod method)
{
List<Component> dependencies = new LinkedList<Component>();
Class[] parameterTypes = method.getParameterTypes();
@@ -606,6 +635,7 @@
public void start()
{
moveComponentsToState(STARTED);
+ shortTermMethodCache = null;
}
/**
@@ -710,10 +740,10 @@
this.instance = instance;
// now scan the instance for all dependencies.
- List<Method> injectionMethods = ReflectionUtil.getAllMethods(instance.getClass(), Inject.class);
+ List<CachedMethod> injectionMethods = lookupInjectionMethods(instance.getClass());
// now for each injection method, get dependencies
- for (Method m : injectionMethods) dependencies.addAll(getDeclaredDependencies(m));
+ for (CachedMethod m : injectionMethods) dependencies.addAll(getDeclaredDependencies(m));
}
/**
@@ -845,10 +875,10 @@
{
try
{
- List<Method> methods = ReflectionUtil.getAllMethods(instance.getClass(), Inject.class);
+ List<CachedMethod> methods = lookupInjectionMethods(instance.getClass());
// search for anything we need to inject
- for (Method method : methods) performInjection(method, instance);
+ for (CachedMethod method : methods) performInjection(method, instance);
}
catch (Exception e)
{
Copied: core/trunk/src/main/java/org/jboss/cache/factories/annotations/CacheInjectionMethods.java (from rev 5322, core/trunk/src/main/java/org/jboss/cache/factories/annotations/Inject.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/annotations/CacheInjectionMethods.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/factories/annotations/CacheInjectionMethods.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -0,0 +1,23 @@
+package org.jboss.cache.factories.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * If this is set on a class, then all methods on that class (and superclasses) annotated with @Inject are cached in the component registry.
+ * Useful for components that are frequently constructed using the component registry during the lifespan of the cache.
+ *
+ * @author Manik Surtani
+ * @see org.jboss.cache.factories.annotations.ComponentName
+ * @since 2.1.0
+ */
+// ensure this annotation is available at runtime.
+(a)Retention(RetentionPolicy.RUNTIME)
+
+// only applies to fields.
+(a)Target(ElementType.TYPE)
+public @interface CacheInjectionMethods
+{
+}
\ No newline at end of file
Added: core/trunk/src/main/java/org/jboss/cache/util/reflect/CachedMethod.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/reflect/CachedMethod.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/reflect/CachedMethod.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -0,0 +1,39 @@
+package org.jboss.cache.util.reflect;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+/**
+ * A cached Method object, so that calls to getParameterTypes, getAnnotations, etc are cached.
+ *
+ * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
+ * @since 2.1.0
+ */
+public class CachedMethod
+{
+ Method method;
+ Class[] parameterTypes;
+ Annotation[][] parameterAnnotations;
+
+ public CachedMethod(Method method)
+ {
+ this.method = method;
+ this.parameterTypes = method.getParameterTypes();
+ this.parameterAnnotations = method.getParameterAnnotations();
+ }
+
+ public Method getMethod()
+ {
+ return method;
+ }
+
+ public Class[] getParameterTypes()
+ {
+ return parameterTypes;
+ }
+
+ public Annotation[][] getParameterAnnotations()
+ {
+ return parameterAnnotations;
+ }
+}
Modified: core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java 2008-02-08 09:32:51 UTC (rev 5332)
+++ core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -37,6 +37,21 @@
}
/**
+ * Returns a set of Methods that contain the given method annotation. This includes all public, protected, package and private
+ * methods, as well as those of superclasses. Note that this does *not* include overridden methods.
+ *
+ * @param c class to inspect
+ * @param annotationType the type of annotation to look for
+ * @return List of Method objects that require injection.
+ */
+ public static List<CachedMethod> getAllCachedMethods(Class c, Class<? extends Annotation> annotationType)
+ {
+ List<CachedMethod> annotated = new LinkedList<CachedMethod>();
+ inspectRecursivelyCached(c, annotated, annotationType);
+ return annotated;
+ }
+
+ /**
* Inspects a class and it's superclasses (all the way to {@link Object} for method instances that contain a given annotation.
* This even identifies private, package and protected methods, not just public ones.
*
@@ -60,6 +75,29 @@
}
/**
+ * Inspects a class and it's superclasses (all the way to {@link Object} for method instances that contain a given annotation.
+ * This even identifies private, package and protected methods, not just public ones.
+ *
+ * @param c
+ * @param s
+ * @param annotationType
+ */
+ private static void inspectRecursivelyCached(Class c, List<CachedMethod> s, Class<? extends Annotation> annotationType)
+ {
+ // Superclass first
+ if (!c.equals(Object.class)) inspectRecursivelyCached(c.getSuperclass(), s, annotationType);
+
+ for (Method m : c.getDeclaredMethods())
+ {
+ // don't bother if this method has already been overridden by a subclass
+ if (!alreadyFoundCached(m, s) && m.isAnnotationPresent(annotationType))
+ {
+ s.add(new CachedMethod(m));
+ }
+ }
+ }
+
+ /**
* Tests whether a method has already been found, i.e., overridden.
*
* @param m method to inspect
@@ -77,6 +115,24 @@
return false;
}
+ /**
+ * Tests whether a method has already been found, i.e., overridden.
+ *
+ * @param m method to inspect
+ * @param s collection of methods found
+ * @return true a method with the same signature already exists.
+ */
+ private static boolean alreadyFoundCached(Method m, Collection<CachedMethod> s)
+ {
+ for (CachedMethod found : s)
+ {
+ if (m.getName().equals(found.getMethod().getName()) &&
+ Arrays.equals(m.getParameterTypes(), found.getParameterTypes()))
+ return true;
+ }
+ return false;
+ }
+
public static void setValue(Object instance, String fieldName, Object value)
{
try
Modified: core/trunk/src/test/java/org/jboss/cache/api/NodeAPITest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/NodeAPITest.java 2008-02-08 09:32:51 UTC (rev 5332)
+++ core/trunk/src/test/java/org/jboss/cache/api/NodeAPITest.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -178,31 +178,6 @@
tm.commit();
}
- public void testImmutabilityOfData()
- {
- rootNode.put("key", "value");
- Map<Object, Object> m = rootNode.getData();
- try
- {
- m.put("x", "y");
- fail("Map should be immutable!!");
- }
- catch (Exception e)
- {
- // expected
- }
-
- try
- {
- rootNode.getKeys().add(new Object());
- fail("Key set should be immutable");
- }
- catch (Exception e)
- {
- // expected
- }
- }
-
public void testImmutabilityOfChildren()
{
rootNode.addChild(A);
Modified: core/trunk/src/test/java/org/jboss/cache/api/NodeSPITest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/NodeSPITest.java 2008-02-08 09:32:51 UTC (rev 5332)
+++ core/trunk/src/test/java/org/jboss/cache/api/NodeSPITest.java 2008-02-08 13:30:51 UTC (rev 5333)
@@ -83,26 +83,26 @@
Map dataDirect = root.getDataDirect();
Set keysDirect = root.getKeysDirect();
- try
- {
- dataDirect.remove("k");
- fail("getDataDirect() should return an unmodifiable collection object");
- }
- catch (UnsupportedOperationException uoe)
- {
- // good; should be immutable
- }
+// try
+// {
+// dataDirect.remove("k");
+// fail("getDataDirect() should return an unmodifiable collection object");
+// }
+// catch (UnsupportedOperationException uoe)
+// {
+// // good; should be immutable
+// }
+//
+// try
+// {
+// keysDirect.clear();
+// fail("getKeysDirect() should return an unmodifiable collection object");
+// }
+// catch (UnsupportedOperationException uoe)
+// {
+// // good; should be immutable
+// }
- try
- {
- keysDirect.clear();
- fail("getKeysDirect() should return an unmodifiable collection object");
- }
- catch (UnsupportedOperationException uoe)
- {
- // good; should be immutable
- }
-
// now test defensive copy
root.put("k2", "v2");
@@ -111,7 +111,7 @@
assertTrue("getKeysDirect() should have made a defensive copy of the data collection object", !keysDirect.contains("k2"));
}
- public void testChildrenImmutabilityAndDefensiveCopy()
+ public void testChildrenDefensiveCopy()
{
// put some stuff in the root node
String childName = "childName";
@@ -119,17 +119,7 @@
root.addChild(new Fqn<String>(childName));
Set childrenDirect = root.getChildrenDirect();
- try
- {
- childrenDirect.clear();
- fail("getChildrenDirect() should return an unmodifiable collection object");
- }
- catch (UnsupportedOperationException uoe)
- {
- // good; should be immutable
- }
-
- // now test defensive copy
+ // test defensive copy
root.addChild(new Fqn<String>(newChild));
assertTrue("root.addChild() should have succeeded", root.getChildrenNamesDirect().contains(newChild));
17 years, 8 months
JBoss Cache SVN: r5332 - in amazon-s3/trunk/src: test/java/com/amazon/s3 and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: genman
Date: 2008-02-08 04:32:51 -0500 (Fri, 08 Feb 2008)
New Revision: 5332
Added:
amazon-s3/trunk/src/test/java/com/amazon/s3/CallingFormatTest.java
amazon-s3/trunk/src/test/java/com/amazon/s3/CanonicalStringTest.java
Modified:
amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java
amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java
amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java
amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java
amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java
Log:
Additional code cleanup, more tests
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -23,8 +23,20 @@
*/
public abstract class CallingFormat {
+ /**
+ * Call by using a path.
+ */
public final static CallingFormat PATH = new PathCallingFormat();
+
+ /**
+ * Call by using a sub-domain of the bucket name.
+ */
public final static CallingFormat SUBDOMAIN = new SubdomainCallingFormat();
+
+ /**
+ * Call using a "vanity" or user-provided hostname.
+ * The bucket name is in fact the domain name.
+ */
public final static CallingFormat VANITY = new VanityCallingFormat();
public abstract boolean supportsLocatedBuckets();
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -1,5 +1,6 @@
package com.amazon.s3;
+import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
@@ -25,6 +26,7 @@
private static final String AMAZON_HEADER_PREFIX = "x-amz-";
private static final String ALTERNATIVE_DATE_HEADER = "x-amz-date";
+ private static final Charset UTF8 = Charset.forName("UTF-8");
/**
* HMAC/SHA1 Algorithm per RFC 2104.
@@ -159,15 +161,13 @@
new SecretKeySpec(awsSecretAccessKey.getBytes(), HMAC_SHA1_ALGORITHM);
return signingKey;
}
-
+
+
/**
* Calculate the HMAC/SHA1 on a string.
- * @param data Data to sign
- * @param passcode Passcode to sign it with
* @return Signature
*/
- static String encode(Key signingKey, String canonicalString,
- boolean urlencode)
+ static String encode(Key signingKey, String canonicalString)
{
Mac mac;
try {
@@ -181,15 +181,9 @@
throw new RuntimeException("Could not initialize the MAC algorithm", e);
}
- byte[] b = mac.doFinal(canonicalString.getBytes());
- byte[] encode = Base64.encodeBase64(b);
- String b64 = EncodingUtil.getAsciiString(encode);
-
- if (urlencode) {
- return UrlEncoder.encode(b64);
- } else {
- return b64;
- }
+ mac.update(UTF8.encode(canonicalString));
+ byte[] encode = Base64.encodeBase64(mac.doFinal());
+ return EncodingUtil.getAsciiString(encode);
}
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -39,15 +39,34 @@
*/
public class Connection {
+ /**
+ * Location default.
+ */
public static final String LOCATION_DEFAULT = null;
+
+ /**
+ * Location in Europe.
+ */
public static final String LOCATION_EU = "EU";
+ /**
+ * Default hostname.
+ */
public static final String DEFAULT_HOST = "s3.amazonaws.com";
+
+ /**
+ * HTTP port.
+ */
public static final int INSECURE_PORT = 80;
+
+ /**
+ * HTTPS port.
+ */
public static final int SECURE_PORT = 443;
/**
* Data larger than 1024 bytes will use expect headers.
+ * See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 14.20
*/
public static final int EXPECT_SIZE = 1024;
@@ -69,14 +88,23 @@
throw new Error("URI charset must be UTF-8: " + charset);
}
+ /**
+ * Constructs a new Connection.
+ */
public Connection(String awsAccessKeyId, String awsSecretAccessKey) {
this(awsAccessKeyId, awsSecretAccessKey, true);
}
+ /**
+ * Constructs a new Connection.
+ */
public Connection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure) {
this(awsAccessKeyId, awsSecretAccessKey, isSecure, DEFAULT_HOST);
}
+ /**
+ * Constructs a new Connection.
+ */
public Connection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
String server)
{
@@ -84,12 +112,18 @@
isSecure ? SECURE_PORT : INSECURE_PORT);
}
+ /**
+ * Constructs a new Connection.
+ */
public Connection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
String server, int port) {
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port, CallingFormat.SUBDOMAIN);
}
+ /**
+ * Constructs a new Connection.
+ */
public Connection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
String server, CallingFormat format) {
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
@@ -174,7 +208,7 @@
}
/**
- * Creates a new bucket.
+ * Creates a new bucket with a location.
*/
public Response create(Bucket bucket, String location) throws IOException {
return create(bucket, location, null);
@@ -182,7 +216,6 @@
/**
* Creates a new bucket.
- * @throws IOException
*/
public Response create(Bucket bucket) throws IOException {
return create(bucket, null);
@@ -569,8 +602,6 @@
/**
* Lists all the buckets created by this account.
- * @param headers A Map of String to List of Strings representing the http
- * headers to pass (can be null).
*/
public ListAllBucketsResponse listAllBuckets(Headers headers)
throws IOException
@@ -705,7 +736,7 @@
Headers prop = new Headers(httpMethod.getRequestHeaders());
String enckey = UrlEncoder.encode(key);
String canonicalString = CanonicalString.make(method, bucket, enckey, pathArgs, prop);
- String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString, false);
+ String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString);
httpMethod.setRequestHeader("Authorization",
"AWS " + this.awsAccessKeyId + ":" + encodedCanonical);
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -48,6 +48,10 @@
return (Date) lastModified.clone();
}
+ /**
+ * Returns the key
+ */
+ @Override
public String toString() {
return getKey();
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -32,7 +32,10 @@
*/
public Headers(Headers headers) {
this();
- this.headers.putAll(headers.headers);
+ for (Map.Entry<String, List<String>> me : headers.headers.entrySet()) {
+ for (String v : me.getValue())
+ put(me.getKey(), v);
+ }
}
/**
@@ -42,6 +45,9 @@
this(new HashMap<String, List<String>>());
}
+ /**
+ * Constructs a new Headers object.
+ */
public Headers(Header[] requestHeaders) {
this();
for (Header h : requestHeaders) {
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -57,14 +57,6 @@
this.currText = new StringBuilder();
}
- public void startDocument() {
- // ignore
- }
-
- public void endDocument() {
- // ignore
- }
-
public void startElement(String uri, String name, String qName,
Attributes attrs) {
if (name.equals("Bucket")) {
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -14,7 +14,10 @@
public enum Method {
GET, PUT, DELETE, HEAD;
- public HttpMethod createHttpMethod() {
+ /**
+ * Returns a new HTTP method for processing.
+ */
+ HttpMethod createHttpMethod() {
switch (this) {
case PUT: return new PutMethod();
case GET: return new GetMethod();
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -227,7 +227,7 @@
String enckey = UrlEncoder.encode(key);
String canonicalString = CanonicalString.make(method, bucket, enckey, pathArgs, headers, ""+expires);
- String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString, false);
+ String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString);
pathArgs.put("Signature", encodedCanonical);
pathArgs.put("Expires", Long.toString(expires));
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -29,7 +29,7 @@
public class Response {
private HttpMethod method;
-
+
Response(HttpMethod method) {
this.method = method;
}
@@ -61,7 +61,13 @@
public void assertOk() {
if (isOk())
return;
- throw new IllegalStateException("Unexpected response: " + this);
+ String msg;
+ try {
+ msg = method.getResponseBodyAsString();
+ } catch (IOException e) {
+ msg = "?";
+ }
+ throw new IllegalStateException("Unexpected response: " + this + " Message: " + msg);
}
/**
@@ -148,7 +154,7 @@
throw new RuntimeException("Unexpected error parsing ListBucket xml", e);
}
}
-
+
static XMLReader createXMLReader() {
try {
return XMLReaderFactory.createXMLReader();
Added: amazon-s3/trunk/src/test/java/com/amazon/s3/CallingFormatTest.java
===================================================================
--- amazon-s3/trunk/src/test/java/com/amazon/s3/CallingFormatTest.java (rev 0)
+++ amazon-s3/trunk/src/test/java/com/amazon/s3/CallingFormatTest.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -0,0 +1,26 @@
+package com.amazon.s3;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.httpclient.URI;
+import org.junit.Test;
+
+public class CallingFormatTest {
+
+ @Test
+ public void testCalling() throws Exception {
+ Bucket bucket = new Bucket("bucket");
+ String key = "/HI";
+ Map<String, String> args = new HashMap<String, String>();
+ args.put("one", "1");
+ URI uri;
+ uri = CallingFormat.PATH.getURI(true, "foo", 444, bucket, key, args);
+ assertEquals("https://foo:444/bucket/%2FHI?one=1", uri.toString());
+ uri = CallingFormat.SUBDOMAIN.getURI(true, "foo", 444, bucket, key, args);
+ assertEquals("https://bucket.foo:444/%2FHI?one=1", uri.toString());
+ }
+
+}
Added: amazon-s3/trunk/src/test/java/com/amazon/s3/CanonicalStringTest.java
===================================================================
--- amazon-s3/trunk/src/test/java/com/amazon/s3/CanonicalStringTest.java (rev 0)
+++ amazon-s3/trunk/src/test/java/com/amazon/s3/CanonicalStringTest.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -0,0 +1,40 @@
+package com.amazon.s3;
+
+import static org.junit.Assert.assertEquals;
+
+import java.security.Key;
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class CanonicalStringTest {
+
+ @Test
+ public void testMacOlder() throws Exception {
+ String access = "213321324ksadjfkasjfdasfdjksadf";
+ String canon = "XXYasfajkjaslkfdjalksjflkasjflkajskfjasjflksadjflksajfdkljsadlkfjaslkfd";
+ Key key = CanonicalString.key(access);
+ String encode = CanonicalString.encode(key, canon);
+ assertEquals("hAu+ibd/CZIw6/5OR69i2+40bfc=", encode);
+ }
+
+ @Test
+ public void testMac2() throws Exception {
+ String access = "213321324ksadjfkasjfdasfdjksadf";
+ String canon = "XXYasfajkjaslkfdjalksjflkasjflkajskfjasjflksadjflksajfdkljsadlkfjaslkfd";
+ Key key = CanonicalString.key(access);
+ String encode = CanonicalString.encode(key, canon);
+ assertEquals("p5p5Y89Qhhaitcesa/l03whnQhw=", encode);
+ }
+
+ @Test
+ public void testMake() throws Exception {
+ Map<String, String> path = Collections.singletonMap("auth", "");
+ Headers h = new Headers();
+ h.put("x", "y");
+ String expires = "whenever";
+ String make = CanonicalString.make(Method.PUT, new Bucket("xyz"), "key", path, h, expires);
+ assertEquals("PUT\n\n\nwhenever\n/xyz/key", make);
+ }
+}
Modified: amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java
===================================================================
--- amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java 2008-02-07 22:57:14 UTC (rev 5331)
+++ amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java 2008-02-08 09:32:51 UTC (rev 5332)
@@ -126,7 +126,7 @@
assertEquals("Unexpected common prefix size", 1, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "", "", 2, "/", true, "test/");
String marker = listBucketResponse.getNextMarker();
- listBucketResponse = conn.list(bucket, null, marker, new Integer( 2 ), "/", null);
+ listBucketResponse = conn.list(bucket, null, marker, 2, "/", null);
listBucketResponse.assertOk();
assertEquals("Unexpected list size", 1, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 0, listBucketResponse.getCommonPrefixEntries().size());
17 years, 8 months
JBoss Cache SVN: r5331 - in amazon-s3/trunk: src/main/java/com/amazon and 4 other directories.
by jbosscache-commits@lists.jboss.org
Author: genman
Date: 2008-02-07 17:57:14 -0500 (Thu, 07 Feb 2008)
New Revision: 5331
Added:
amazon-s3/trunk/src/main/java/com/amazon/s3/GetStreamResponse.java
amazon-s3/trunk/src/test/resources/
amazon-s3/trunk/src/test/resources/log4j.xml
Removed:
amazon-s3/trunk/src/main/java/com/amazon/thirdparty/
Modified:
amazon-s3/trunk/.classpath
amazon-s3/trunk/pom.xml
amazon-s3/trunk/src/main/java/com/amazon/s3/Bucket.java
amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java
amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java
amazon-s3/trunk/src/main/java/com/amazon/s3/GetResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java
amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/LocationResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java
amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java
amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java
amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java
Log:
Use Apache HTTP client library instead of Java URL Connection.
It's more efficient (uses the same Socket) and supports more options, like "HTTP expect" exchanges
Modified: amazon-s3/trunk/.classpath
===================================================================
--- amazon-s3/trunk/.classpath 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/.classpath 2008-02-07 22:57:14 UTC (rev 5331)
@@ -2,6 +2,7 @@
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
Modified: amazon-s3/trunk/pom.xml
===================================================================
--- amazon-s3/trunk/pom.xml 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/pom.xml 2008-02-07 22:57:14 UTC (rev 5331)
@@ -1,13 +1,9 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<?xml version="1.0" encoding="UTF-8"?><project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.amazon</groupId>
<artifactId>amazon-s3-rest</artifactId>
<version>1.0.0.0-SNAPSHOT</version>
- <description>
- Cleaned-up version of the Amazon S3 REST access layer
- </description>
+ <description>Cleaned-up version of the Amazon S3 REST access layer</description>
<build>
<plugins>
<plugin>
@@ -18,7 +14,6 @@
</configuration>
</plugin>
<plugin>
- <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
@@ -42,5 +37,21 @@
<version>4.1</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.0.1</version>
+ </dependency>
</dependencies>
-</project>
+</project>
\ No newline at end of file
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Bucket.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Bucket.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Bucket.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -92,7 +92,7 @@
* Returns true if the bucket name is valid for the calling format.
*/
public static boolean validateBucketName(String bucketName, CallingFormat callingFormat) {
- if (callingFormat == CallingFormat.getPathCallingFormat())
+ if (callingFormat == CallingFormat.PATH)
{
final int MIN_BUCKET_LENGTH = 3;
final int MAX_BUCKET_LENGTH = 255;
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -9,10 +9,13 @@
package com.amazon.s3;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.Map;
+import org.apache.commons.httpclient.HttpURL;
+import org.apache.commons.httpclient.HttpsURL;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.URIException;
+
/**
* Calling formats.
*
@@ -20,9 +23,9 @@
*/
public abstract class CallingFormat {
- private final static CallingFormat pathCallingFormat = new PathCallingFormat();
- private final static CallingFormat subdomainCallingFormat = new SubdomainCallingFormat();
- private final static CallingFormat vanityCallingFormat = new VanityCallingFormat();
+ public final static CallingFormat PATH = new PathCallingFormat();
+ public final static CallingFormat SUBDOMAIN = new SubdomainCallingFormat();
+ public final static CallingFormat VANITY = new VanityCallingFormat();
public abstract boolean supportsLocatedBuckets();
@@ -30,71 +33,57 @@
public abstract String getPathBase(Bucket bucket, String key);
- public abstract URL getURL(boolean isSecure, String server, int port,
+ public abstract URI getURI(boolean isSecure, String server, int port,
Bucket bucket, String key, Map<String, String> pathArgs)
- throws MalformedURLException;
+ throws URIException;
/**
- * Converts the Path Arguments from a map to String which can be used in url construction
- * @param pathArgs a map of arguments
- * @return a string representation of pathArgs
+ * Adds query parameters to the URL.
*/
- public static String convertPathArgsHashToString(Map<String, String> pathArgs) {
- StringBuilder pathArgsString = new StringBuilder();
- String argumentValue;
- boolean firstRun = true;
- if (pathArgs != null) {
- for (Map.Entry<String, String> me : pathArgs.entrySet()) {
- String argument = me.getKey();
- if (firstRun) {
- firstRun = false;
- pathArgsString.append("?");
- } else {
- pathArgsString.append("&");
- }
-
- argumentValue = me.getValue();
- pathArgsString.append(argument);
- if (argumentValue != null) {
- pathArgsString.append("=");
- pathArgsString.append(argumentValue);
- }
- }
+ private static URI addQuery(HttpURL uri, Map<String, String> pathArgs) throws URIException {
+ if (pathArgs == null || pathArgs.isEmpty())
+ return uri;
+ int size = pathArgs.size();
+ String[] name = new String[size];
+ String[] value = new String[size];
+ int i = 0;
+ for (Map.Entry<String, String> me : pathArgs.entrySet()) {
+ name[i] = me.getKey();
+ value[i] = me.getValue();
+ if (value[i] == null)
+ throw new NullPointerException("query cannot contain null " + pathArgs);
+ i++;
}
-
- return pathArgsString.toString();
+ uri.setQuery(name, value);
+ return uri;
}
- public static CallingFormat getPathCallingFormat() {
- return pathCallingFormat;
+ private static URI url(boolean isSecure, String host, int port, String path, Map<String, String> pathArgs)
+ throws URIException
+ {
+ HttpURL url = isSecure ? new HttpsURL(host, port, "/") : new HttpURL(host, port, "/");
+ url.setEscapedPath(path);
+ return addQuery(url, pathArgs);
}
- public static CallingFormat getSubdomainCallingFormat() {
- return subdomainCallingFormat;
- }
-
- public static CallingFormat getVanityCallingFormat() {
- return vanityCallingFormat;
- }
-
static private class PathCallingFormat extends CallingFormat {
public boolean supportsLocatedBuckets() {
return false;
}
public String getPathBase(Bucket bucket, String key) {
- return isBucketSpecified(bucket) ? "/" + bucket + "/" + key : "/";
+ return isBucketSpecified(bucket) ? "/" + bucket + "/" + UrlEncoder.encode(key) : "/";
}
public String getEndpoint(String server, int port, Bucket bucket) {
return server + ":" + port;
}
- public URL getURL(boolean isSecure, String server, int port, Bucket bucket, String key, Map<String, String> pathArgs)
- throws MalformedURLException {
- String pathBase = isBucketSpecified(bucket) ? "/" + bucket + "/" + key : "/";
- String pathArguments = convertPathArgsHashToString(pathArgs);
- return new URL(isSecure ? "https" : "http", server, port, pathBase + pathArguments);
+ @Override
+ public URI getURI(boolean isSecure, String server, int port, Bucket bucket, String key, Map<String, String> pathArgs)
+ throws URIException {
+ String pathBase = isBucketSpecified(bucket) ? "/" + bucket + "/" + UrlEncoder.encode(key) : "/";
+ return url(isSecure, server, port, pathBase, pathArgs);
}
private boolean isBucketSpecified(Bucket bucket) {
@@ -120,22 +109,19 @@
}
public String getPathBase(Bucket bucket, String key) {
- return "/" + key;
+ return "/" + UrlEncoder.encode(key);
}
- public URL getURL(boolean isSecure, String server, int port,
+ @Override
+ public URI getURI(boolean isSecure, String server, int port,
Bucket bucket, String key, Map<String, String> pathArgs)
- throws MalformedURLException {
+ throws URIException {
if (bucket == null || !bucket.specified()) {
- // The bucket is null, this is listAllBuckets request
- String pathArguments = convertPathArgsHashToString(pathArgs);
- return new URL(isSecure ? "https" : "http", server, port, "/"
- + pathArguments);
+ return url(isSecure, server, port, "", pathArgs);
} else {
String serverToUse = getServer(server, bucket);
String pathBase = getPathBase(bucket, key);
- String pathArguments = convertPathArgsHashToString(pathArgs);
- return new URL(isSecure ? "https" : "http", serverToUse, port, pathBase + pathArguments);
+ return url(isSecure, serverToUse, port, pathBase, pathArgs);
}
}
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/CanonicalString.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -12,7 +12,8 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import com.amazon.thirdparty.Base64;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.util.EncodingUtil;
/**
* Creates canonical strings for authorization purposes by hashing
@@ -109,7 +110,7 @@
// append the key (it might be an empty string)
// append a slash regardless
buf.append("/");
- if(key != null) {
+ if (key != null) {
buf.append(key);
}
@@ -164,29 +165,25 @@
* @param data Data to sign
* @param passcode Passcode to sign it with
* @return Signature
- * @throws NoSuchAlgorithmException If the algorithm does not exist. Unlikely
- * @throws InvalidKeyException If the key is invalid.
*/
static String encode(Key signingKey, String canonicalString,
boolean urlencode)
{
- // Acquire the MAC instance and initialize with the signing key.
- Mac mac = null;
+ Mac mac;
try {
mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
- // should not happen
throw new RuntimeException("Could not find sha1 algorithm", e);
}
try {
mac.init(signingKey);
} catch (InvalidKeyException e) {
- // also should not happen
throw new RuntimeException("Could not initialize the MAC algorithm", e);
}
- // Compute the HMAC on the digest, and set it.
- String b64 = Base64.encodeBytes(mac.doFinal(canonicalString.getBytes()));
+ byte[] b = mac.doFinal(canonicalString.getBytes());
+ byte[] encode = Base64.encodeBase64(b);
+ String b64 = EncodingUtil.getAsciiString(encode);
if (urlencode) {
return UrlEncoder.encode(b64);
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -10,8 +10,6 @@
package com.amazon.s3;
import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Collections;
@@ -22,6 +20,17 @@
import java.util.Map;
import java.util.TimeZone;
+import org.apache.commons.httpclient.HostConfiguration;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+
/**
* A stateless connection to the Amazon S3 system which uses the REST API.
* <p/>
@@ -36,6 +45,11 @@
public static final String DEFAULT_HOST = "s3.amazonaws.com";
public static final int INSECURE_PORT = 80;
public static final int SECURE_PORT = 443;
+
+ /**
+ * Data larger than 1024 bytes will use expect headers.
+ */
+ public static final int EXPECT_SIZE = 1024;
private String awsAccessKeyId;
private Key awsSecretAccessKey;
@@ -44,6 +58,17 @@
private int port;
private CallingFormat callingFormat;
+ private MultiThreadedHttpConnectionManager connectionManager =
+ new MultiThreadedHttpConnectionManager();
+ private HostConfiguration config;
+ private HttpClient client;
+
+ static {
+ String charset = URI.getDefaultProtocolCharset();
+ if (!charset.equals("UTF-8"))
+ throw new Error("URI charset must be UTF-8: " + charset);
+ }
+
public Connection(String awsAccessKeyId, String awsSecretAccessKey) {
this(awsAccessKeyId, awsSecretAccessKey, true);
}
@@ -61,7 +86,7 @@
public Connection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
String server, int port) {
- this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port, CallingFormat.getSubdomainCallingFormat());
+ this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port, CallingFormat.SUBDOMAIN);
}
@@ -69,7 +94,7 @@
String server, CallingFormat format) {
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
isSecure ? SECURE_PORT : INSECURE_PORT,
- CallingFormat.getSubdomainCallingFormat());
+ CallingFormat.SUBDOMAIN);
}
/**
@@ -92,6 +117,11 @@
this.server = server;
this.port = port;
this.callingFormat = format;
+
+ config = new HostConfiguration();
+ config.setHost(server, port, isSecure ? "http" : "https");
+ client = new HttpClient(connectionManager);
+ client.setHostConfiguration(config);
}
/**
@@ -121,14 +151,27 @@
if (!bucket.validateName(callingFormat))
throw new IllegalArgumentException("Invalid Bucket Name: "+bucket);
- HttpURLConnection request = makeRequest(Method.PUT, bucket, headers);
+ PutMethod method = (PutMethod) makeRequest(Method.PUT, bucket, headers);
if (body != null)
{
- request.setDoOutput(true);
- request.getOutputStream().write(body.getBytes("UTF-8"));
+ StringRequestEntity sre = new StringRequestEntity(body, "text/xml", "UTF-8");
+ method.setRequestEntity(sre);
}
- return new Response(request);
+ executeRelease(method);
+ return new Response(method);
}
+
+ private int execute(HttpMethod method) throws IOException {
+ return client.executeMethod(method);
+ }
+
+ private int executeRelease(HttpMethod method) throws IOException {
+ try {
+ return client.executeMethod(method);
+ } finally {
+ method.releaseConnection();
+ }
+ }
/**
* Creates a new bucket.
@@ -153,8 +196,8 @@
*/
public boolean exists(Bucket bucket) throws IOException
{
- HttpURLConnection response = makeRequest(Method.HEAD, bucket);
- int httpCode = response.getResponseCode();
+ HttpMethod method = makeRequest(Method.HEAD, bucket);
+ int httpCode = executeRelease(method);
return httpCode >= 200 && httpCode < 300;
}
@@ -201,7 +244,7 @@
}
/**
- * Lists the contents of a bucket.
+ * Lists the contents of a bucket by prefix.
*/
public ListResponse list(Bucket bucket, String prefix) throws IOException {
return list(bucket, prefix, null, null);
@@ -224,10 +267,34 @@
throws IOException
{
- Map<String, String> pathArgs = Response.paramsForListOptions(prefix, marker, maxKeys, delimiter);
- return new ListResponse(makeRequest(Method.GET, bucket, pathArgs, headers));
+ Map<String, String> pathArgs = paramsForListOptions(prefix, marker, maxKeys, delimiter);
+ HttpMethod method = makeRequest(Method.GET, bucket, pathArgs, headers);
+ try {
+ execute(method);
+ return new ListResponse(method);
+ } finally {
+ method.releaseConnection();
+ }
}
+ private static Map<String, String> paramsForListOptions(String prefix,
+ String marker, Integer maxKeys, String delimiter)
+ {
+ Map<String, String> argParams = new HashMap<String, String>();
+ if (prefix != null)
+ argParams.put("prefix", prefix);
+ if (marker != null)
+ argParams.put("marker", marker);
+ if (delimiter != null)
+ argParams.put("delimiter", delimiter);
+
+ if (maxKeys != null)
+ argParams.put("max-keys", Integer.toString(maxKeys.intValue()));
+
+ return argParams;
+
+ }
+
/**
* Deletes a bucket.
* @param bucket The name of the bucket to delete.
@@ -237,7 +304,9 @@
public Response delete(Bucket bucket, Headers headers)
throws IOException
{
- return new Response(makeRequest(Method.DELETE, bucket, "", null, headers));
+ HttpMethod method = makeRequest(Method.DELETE, bucket, "", null, headers);
+ executeRelease(method);
+ return new Response(method);
}
/**
@@ -260,13 +329,8 @@
public Response put(Bucket bucket, String key, S3Object object, Headers headers)
throws IOException
{
- HttpURLConnection request =
- makeRequest(Method.PUT, bucket, key, null, headers, object);
-
- request.setDoOutput(true);
- request.getOutputStream().write(object.getData() == null ? new byte[] {} : object.getData());
-
- return new Response(request);
+ PutMethod request = (PutMethod) makeRequest(Method.PUT, bucket, key, null, headers, object);
+ return execute(request, object);
}
/**
@@ -280,13 +344,18 @@
* Reads an object from S3.
* @param bucket The name of the bucket where the object lives.
* @param key The name of the key to use.
- * @param headers A Map of String to List of Strings representing the http
- * headers to pass (can be null).
+ * @param headers HTTP headers to pass (can be null).
*/
public GetResponse get(Bucket bucket, String key, Headers headers)
throws IOException
{
- return new GetResponse(makeRequest(Method.GET, bucket, key, null, headers));
+ HttpMethod method = makeRequest(Method.GET, bucket, key, null, headers);
+ try {
+ execute(method);
+ return new GetResponse(method);
+ } finally {
+ method.releaseConnection();
+ }
}
/**
@@ -298,6 +367,39 @@
}
/**
+ * Reads an object from S3, returning a stream to access the data.
+ * This is preferable when dealing with large objects.
+ *
+ * @param bucket The name of the bucket where the object lives.
+ * @param key The name of the key to use.
+ * @param headers HTTP headers to pass (can be null).
+ */
+ public GetStreamResponse getStream(Bucket bucket, String key, Headers headers)
+ throws IOException
+ {
+ HttpMethod method = makeRequest(Method.GET, bucket, key, null, headers);
+ boolean ok = false;
+ try {
+ execute(method);
+ ok = true;
+ return new GetStreamResponse((GetMethod)method);
+ } finally {
+ if (!ok)
+ method.releaseConnection();
+ }
+ }
+
+ /**
+ * Reads an object from S3, returning a stream to access the data.
+ * This is preferable when dealing with large objects.
+ */
+ public GetStreamResponse getStream(Bucket bucket, String key)
+ throws IOException
+ {
+ return getStream(bucket, key, null);
+ }
+
+ /**
* Returns information about an S3 object without loading it.
* Check {@link Response#isOk()} or {@link Response#isNotFound()} to see if the object exists.
*/
@@ -309,7 +411,9 @@
* Returns information about an S3 object without loading it.
*/
public Response head(Bucket bucket, String key, Headers headers) throws IOException {
- return new Response(makeRequest(Method.HEAD, bucket, key, null, headers));
+ HttpMethod method = makeRequest(Method.HEAD, bucket, key, null, headers);
+ executeRelease(method);
+ return new Response(method);
}
/**
@@ -322,7 +426,9 @@
public Response delete(Bucket bucket, String key, Headers headers)
throws IOException
{
- return new Response(makeRequest(Method.DELETE, bucket, key, null, headers));
+ HttpMethod method = makeRequest(Method.DELETE, bucket, key, null, headers);
+ executeRelease(method);
+ return new Response(method);
}
/**
@@ -342,8 +448,14 @@
public GetResponse getBucketLogging(Bucket bucket, Headers headers)
throws IOException
{
- Map<String, String> pathArgs = Collections.singletonMap("logging", null);
- return new GetResponse(makeRequest(Method.GET, bucket, "", pathArgs, headers));
+ Map<String, String> pathArgs = Collections.singletonMap("logging", "");
+ HttpMethod method = makeRequest(Method.GET, bucket, "", pathArgs, headers);
+ try {
+ execute(method);
+ return new GetResponse(method);
+ } finally {
+ method.releaseConnection();
+ }
}
/**
@@ -356,13 +468,18 @@
public Response putBucketLogging(Bucket bucket, String loggingXMLDoc, Headers headers)
throws IOException
{
- Map<String, String> pathArgs = Collections.singletonMap("logging", null);
+ Map<String, String> pathArgs = Collections.singletonMap("logging", "");
S3Object object = new S3Object(loggingXMLDoc.getBytes(), null);
- HttpURLConnection request = makeRequest(Method.PUT, bucket, "", pathArgs, headers, object);
-
- request.setDoOutput(true);
- request.getOutputStream().write(object.getData() == null ? new byte[] {} : object.getData());
-
+ PutMethod request = (PutMethod) makeRequest(Method.PUT, bucket, "", pathArgs, headers, object);
+ return execute(request, object);
+ }
+
+ private Response execute(PutMethod request, S3Object object) throws IOException {
+ if (object.getLength() > EXPECT_SIZE)
+ request.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true);
+ // request.setContentChunked(true);
+ request.setRequestEntity(new ByteArrayRequestEntity(object.getData()));
+ executeRelease(request);
return new Response(request);
}
@@ -391,10 +508,14 @@
if (key == null)
key = "";
- Map<String, String> pathArgs = Collections.singletonMap("acl", null);
- return new GetResponse(
- makeRequest(Method.GET, bucket, key, pathArgs, headers)
- );
+ Map<String, String> pathArgs = Collections.singletonMap("acl", "");
+ HttpMethod method = makeRequest(Method.GET, bucket, key, pathArgs, headers);
+ try {
+ execute(method);
+ return new GetResponse(method);
+ } finally {
+ method.releaseConnection();
+ }
}
/**
@@ -421,18 +542,12 @@
public Response putACL(Bucket bucket, String key, String aclXMLDoc, Headers headers)
throws IOException
{
- S3Object object = new S3Object(aclXMLDoc.getBytes(), null);
-
- Map<String, String> pathArgs = new HashMap<String, String>();
- pathArgs.put("acl", null);
+ S3Object object = new S3Object(aclXMLDoc);
+ Map<String, String> pathArgs = Collections.singletonMap("acl", "");
+ PutMethod request =
+ (PutMethod) makeRequest(Method.PUT, bucket, key, pathArgs, headers, object);
+ return execute(request, object);
- HttpURLConnection request =
- makeRequest(Method.PUT, bucket, key, pathArgs, headers, object);
-
- request.setDoOutput(true);
- request.getOutputStream().write(object.getData() == null ? new byte[] {} : object.getData());
-
- return new Response(request);
}
/**
@@ -441,9 +556,14 @@
public LocationResponse getLocation(Bucket bucket)
throws IOException
{
- Map<String, String> pathArgs = new HashMap<String, String>();
- pathArgs.put("location", null);
- return new LocationResponse(makeRequest(Method.GET, bucket, "", pathArgs, null));
+ Map<String, String> pathArgs = Collections.singletonMap("location", "");
+ HttpMethod method = makeRequest(Method.GET, bucket, "", pathArgs, null);
+ try {
+ execute(method);
+ return new LocationResponse(method);
+ } finally {
+ method.releaseConnection();
+ }
}
@@ -455,7 +575,13 @@
public ListAllBucketsResponse listAllBuckets(Headers headers)
throws IOException
{
- return new ListAllBucketsResponse(makeRequest(Method.GET, null, "", null, headers));
+ HttpMethod method = makeRequest(Method.GET, null, "", null, headers);
+ try {
+ execute(method);
+ return new ListAllBucketsResponse(method);
+ } finally {
+ method.releaseConnection();
+ }
}
/**
@@ -467,7 +593,7 @@
}
/**
- * Make a new HttpURLConnection without passing an S3Object parameter.
+ * Make a new HttpMethod without passing an S3Object parameter.
* Use this method for key operations that do require arguments
* @param method The method to invoke
* @param bucketName the bucket this request is for
@@ -477,27 +603,27 @@
* @return
* @throws IOException
*/
- private HttpURLConnection makeRequest(Method method, Bucket bucket, String key, Map<String, String> pathArgs, Headers headers)
+ private HttpMethod makeRequest(Method method, Bucket bucket, String key, Map<String, String> pathArgs, Headers headers)
throws IOException
{
return makeRequest(method, bucket, key, pathArgs, headers, null);
}
- private HttpURLConnection makeRequest(Method method, Bucket bucket) throws IOException {
+ private HttpMethod makeRequest(Method method, Bucket bucket) throws IOException {
return makeRequest(method, bucket, null);
}
- private HttpURLConnection makeRequest(Method method, Bucket bucket, Headers headers) throws IOException {
+ private HttpMethod makeRequest(Method method, Bucket bucket, Headers headers) throws IOException {
return makeRequest(method, bucket, null, headers);
}
- private HttpURLConnection makeRequest(Method method, Bucket bucket, Map<String, String> pathArgs, Headers headers) throws IOException
+ private HttpMethod makeRequest(Method method, Bucket bucket, Map<String, String> pathArgs, Headers headers) throws IOException
{
return makeRequest(method, bucket, "", pathArgs, headers);
}
/**
- * Make a new HttpURLConnection.
+ * Make a new HttpMethod.
* @param method The HTTP method to use (GET, PUT, DELETE)
* @param bucketNamePattern The bucket name this request affects
* @param key The key this request is for, not encoded
@@ -506,89 +632,81 @@
* headers to pass (can be null).
* @param object The S3Object that is to be written (can be null).
*/
- private HttpURLConnection makeRequest(Method method, Bucket bucket, String key, Map<String, String> pathArgs, Headers headers,
+ private HttpMethod makeRequest(Method method, Bucket bucket, String key, Map<String, String> pathArgs, Headers headers,
S3Object object)
throws IOException
{
- String enckey = UrlEncoder.encode(key);
- // build the domain based on the calling format
- URL url = this.callingFormat.getURL(this.isSecure, server, this.port, bucket, enckey, pathArgs);
-
- HttpURLConnection connection = (HttpURLConnection)url.openConnection();
- connection.setRequestMethod(method.name());
-
- // subdomain-style urls may encounter http redirects.
- // Ensure that redirects are supported.
- if (!connection.getInstanceFollowRedirects()
- && callingFormat.supportsLocatedBuckets())
- throw new RuntimeException("HTTP redirect support required.");
-
- addHeaders(connection, headers);
+ HttpMethod httpMethod = method.createHttpMethod();
+
+ URI uri = this.callingFormat.getURI(this.isSecure, server, this.port, bucket, key, pathArgs);
+
+ httpMethod.setURI(uri);
+ addHeaders(httpMethod, headers);
if (object != null)
- addMetadataHeaders(connection, object.getMetadata());
- addAuthHeader(connection, method, bucket, enckey, pathArgs);
-
- return connection;
+ addMetadataHeaders(httpMethod, object.getMetadata());
+ addAuthHeader(httpMethod, method, bucket, key, pathArgs);
+ return httpMethod;
}
/**
- * Add the given headers to the HttpURLConnection.
- * @param connection The HttpURLConnection to which the headers will be added.
+ * Add the given headers to the HttpMethod.
+ * @param httpMethod The HttpMethod to which the headers will be added.
* @param headers A Map of String to List of Strings representing the http
* headers to pass (can be null).
*/
- private void addHeaders(HttpURLConnection connection, Headers headers) {
- addHeaders(connection, headers, "");
+ private void addHeaders(HttpMethod httpMethod, Headers headers) {
+ addHeaders(httpMethod, headers, "");
}
/**
- * Add the given metadata fields to the HttpURLConnection.
- * @param connection The HttpURLConnection to which the headers will be added.
+ * Add the given metadata fields to the HttpMethod.
+ * @param httpMethod The HttpMethod to which the headers will be added.
* @param metadata A Map of String to List of Strings representing the s3
* metadata for this resource.
*/
- private void addMetadataHeaders(HttpURLConnection connection, Headers metadata) {
- addHeaders(connection, metadata, Headers.METADATA_PREFIX);
+ private void addMetadataHeaders(HttpMethod httpMethod, Headers metadata) {
+ addHeaders(httpMethod, metadata, Headers.METADATA_PREFIX);
}
/**
- * Add the given headers to the HttpURLConnection with a prefix before the keys.
- * @param connection The HttpURLConnection to which the headers will be added.
+ * Add the given headers to the HttpMethod with a prefix before the keys.
+ * @param httpMethod The HttpMethod to which the headers will be added.
* @param headers A Map of String to List of Strings representing the http
* headers to pass (can be null).
* @param prefix The string to prepend to each key before adding it to the connection.
*/
- private void addHeaders(HttpURLConnection connection, Headers headers, String prefix) {
+ private void addHeaders(HttpMethod httpMethod, Headers headers, String prefix) {
if (headers != null) {
for (Map.Entry<String, List<String>> me : headers.getHeaders().entrySet()) {
String key = me.getKey();
for (String value : me.getValue()) {
- connection.addRequestProperty(prefix + key, value);
+ httpMethod.addRequestHeader(prefix + key, value);
}
}
}
}
/**
- * Add the appropriate Authorization header to the HttpURLConnection.
- * @param connection The HttpURLConnection to which the header will be added.
+ * Add the appropriate Authorization header to the HttpMethod.
+ * @param httpMethod The HttpMethod to which the header will be added.
* @param method The HTTP method to use (GET, PUT, DELETE)
* @param bucket the bucket name this request is for
* @param key the key this request is for (not URL encoded)
* @param pathArgs path arguments which are part of this request
*/
- private void addAuthHeader(HttpURLConnection connection, Method method, Bucket bucket, String enckey, Map<String, String> pathArgs) {
- if (connection.getRequestProperty("Date") == null) {
- connection.setRequestProperty("Date", httpDate());
+ private void addAuthHeader(HttpMethod httpMethod, Method method, Bucket bucket, String key, Map<String, String> pathArgs) {
+ if (httpMethod.getRequestHeader("Date") == null) {
+ httpMethod.setRequestHeader("Date", httpDate());
}
- if (connection.getRequestProperty("Content-Type") == null) {
- connection.setRequestProperty("Content-Type", "");
+ if (httpMethod.getRequestHeader("Content-Type") == null) {
+ httpMethod.setRequestHeader("Content-Type", "");
}
- Headers prop = new Headers(connection.getRequestProperties());
+ Headers prop = new Headers(httpMethod.getRequestHeaders());
+ String enckey = UrlEncoder.encode(key);
String canonicalString = CanonicalString.make(method, bucket, enckey, pathArgs, prop);
String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString, false);
- connection.setRequestProperty("Authorization",
+ httpMethod.setRequestHeader("Authorization",
"AWS " + this.awsAccessKeyId + ":" + encodedCanonical);
}
@@ -603,6 +721,13 @@
}
/**
+ * Shuts down any managed or pooled connections.
+ */
+ public void shutdown() {
+ connectionManager.shutdown();
+ }
+
+ /**
* Returns a debug string.
*/
@Override
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/GetResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/GetResponse.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/GetResponse.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -12,25 +12,22 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.HttpURLConnection;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpMethodBase;
+
/**
- * A Response object returned from AWSAuthConnection.get(). Exposes the
- * attribute object, which represents the retrieved object.
+ * Returned by the {@link Connection#get(Bucket, String)} methods.
*/
public class GetResponse extends Response {
private S3Object object;
- /**
- * Pulls a representation of an S3Object out of the HttpURLConnection
- * response.
- */
- GetResponse(HttpURLConnection connection) throws IOException {
- super(connection);
- if (connection.getResponseCode() < 400) {
- int len = connection.getContentLength();
- byte[] body = slurpInputStream(connection.getInputStream(), len);
+ GetResponse(HttpMethod method) throws IOException {
+ super(method);
+ if (getResponseCode() < 400) {
+ long len = ((HttpMethodBase)method).getResponseContentLength();
+ byte[] body = toByteArray(method.getResponseBodyAsStream(), len);
object = new S3Object(body, getHeaders().extractMetadata());
}
}
@@ -38,22 +35,21 @@
/**
* Read the input stream and dump it all into a big byte array
*/
- private static byte[] slurpInputStream(InputStream stream, int len) throws IOException {
-
+ private static byte[] toByteArray(InputStream stream, long len) throws IOException {
final int chunkSize = 4 * 1024;
byte[] buf = new byte[chunkSize];
- ByteArrayOutputStream byteStream;
- if (len > 0) {
- byteStream = new ByteArrayOutputStream(len);
+ ByteArrayOutputStream baos;
+ if (len != -1) {
+ baos = new ByteArrayOutputStream((int)len);
} else {
- byteStream = new ByteArrayOutputStream(chunkSize);
+ baos = new ByteArrayOutputStream(chunkSize);
}
int count;
while ((count = stream.read(buf)) != -1)
- byteStream.write(buf, 0, count);
+ baos.write(buf, 0, count);
- return byteStream.toByteArray();
+ return baos.toByteArray();
}
/**
Added: amazon-s3/trunk/src/main/java/com/amazon/s3/GetStreamResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/GetStreamResponse.java (rev 0)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/GetStreamResponse.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -0,0 +1,67 @@
+// This software code is made available "AS IS" without warranties of any
+// kind. You may copy, display, modify and redistribute the software
+// code either by itself or as incorporated into your code; provided that
+// you do not remove any proprietary notices. Your use of this software
+// code is at your own risk and you waive any claim against Amazon
+// Digital Services, Inc. or its affiliates with respect to your use of
+// this software code. (c) 2006 Amazon Digital Services, Inc. or its
+// affiliates.
+
+package com.amazon.s3;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+
+/**
+ * A Response object returned from Connection.getStream().
+ * This response, once read, must be released by calling {@link #release()}.
+ */
+public class GetStreamResponse extends Response {
+
+ private GetMethod method;
+
+ /**
+ * Pulls a representation of an S3Object out of the HttpURLConnection
+ * response.
+ */
+ GetStreamResponse(GetMethod method) throws IOException {
+ super(method);
+ this.method = method;
+ }
+
+ /**
+ * Returns an input stream for the content.
+ * Call {@link #release}) after done reading.
+ * @throws IOException
+ */
+ public InputStream getInputStream() throws IOException {
+ InputStream body = method.getResponseBodyAsStream();
+ if (body == null)
+ throw new IllegalStateException("body null");
+ return body;
+ }
+
+ /**
+ * Returns the content length, if known.
+ */
+ public long getLength() {
+ return method.getResponseContentLength();
+ }
+
+ /**
+ * Releases this connection.
+ */
+ public void release() {
+ method.releaseConnection();
+ }
+
+ /**
+ * Returns a debug string.
+ */
+ @Override
+ public String toString() {
+ return super.toString() + " method=" + method;
+ }
+}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Headers.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -7,6 +7,8 @@
import java.util.Map;
import java.util.TreeMap;
+import org.apache.commons.httpclient.Header;
+
/**
* HTTP header wrapper.
*
@@ -40,6 +42,13 @@
this(new HashMap<String, List<String>>());
}
+ public Headers(Header[] requestHeaders) {
+ this();
+ for (Header h : requestHeaders) {
+ put(h.getName(), h.getValue());
+ }
+ }
+
/**
* Adds a header.
*/
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -10,7 +10,6 @@
package com.amazon.s3;
import java.io.IOException;
-import java.net.HttpURLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -18,6 +17,7 @@
import java.util.List;
import java.util.TimeZone;
+import org.apache.commons.httpclient.HttpMethod;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
@@ -28,8 +28,8 @@
private List<Bucket> entries;
- ListAllBucketsResponse(HttpURLConnection connection) throws IOException {
- super(connection);
+ ListAllBucketsResponse(HttpMethod method) throws IOException {
+ super(method);
if (isOk()) {
entries = new ArrayList<Bucket>();
parse(new ListAllMyBucketsHandler());
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -10,13 +10,13 @@
package com.amazon.s3;
import java.io.IOException;
-import java.net.HttpURLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
+import org.apache.commons.httpclient.HttpMethod;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
@@ -43,8 +43,8 @@
private List<CommonPrefixEntry> commonPrefixEntries = null;
- ListResponse(HttpURLConnection connection) throws IOException {
- super(connection);
+ ListResponse(HttpMethod method) throws IOException {
+ super(method);
if (isOk()) {
parse(new ListBucketHandler());
}
@@ -238,13 +238,13 @@
@Override
public String toString() {
return super.toString() +
+ " entries=" + entries +
" name=" + name +
" prefix=" + prefix +
" marker=" + marker +
" maxKeys=" + maxKeys +
" isTruncated=" + isTruncated +
" nextMarker=" + nextMarker +
- " entries=" + entries +
" prefix=" + commonPrefixEntries;
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/LocationResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/LocationResponse.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/LocationResponse.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -10,8 +10,8 @@
package com.amazon.s3;
import java.io.IOException;
-import java.net.HttpURLConnection;
+import org.apache.commons.httpclient.HttpMethod;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
@@ -27,8 +27,8 @@
/**
* Parse the response to a ?location query.
*/
- LocationResponse(HttpURLConnection connection) throws IOException {
- super(connection);
+ LocationResponse(HttpMethod method) throws IOException {
+ super(method);
if (isOk()) {
parse(new LocationResponseHandler());
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Method.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -1,10 +1,26 @@
package com.amazon.s3;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+
/**
* HTTP Methods.
*
* @author Elias Ross
*/
public enum Method {
- GET, PUT, DELETE, HEAD
+ GET, PUT, DELETE, HEAD;
+
+ public HttpMethod createHttpMethod() {
+ switch (this) {
+ case PUT: return new PutMethod();
+ case GET: return new GetMethod();
+ case DELETE: return new DeleteMethod();
+ case HEAD: return new HeadMethod();
+ }
+ throw new Error();
+ }
}
\ No newline at end of file
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/QueryGenerator.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -9,12 +9,13 @@
package com.amazon.s3;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.io.IOException;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
+import org.apache.commons.httpclient.URI;
+
/**
* Generates URL Query Strings that can be used to perform operations.
* These parameters include an expiration date, so that
@@ -56,7 +57,7 @@
boolean isSecure, String server, int port)
{
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
- port, CallingFormat.getSubdomainCallingFormat());
+ port, CallingFormat.SUBDOMAIN);
}
public QueryGenerator(String awsAccessKeyId, String awsSecretAccessKey,
@@ -96,32 +97,32 @@
expires = null;
}
- public URL create(Bucket bucket, Headers headers)
+ public URI create(Bucket bucket, Headers headers)
{
// validate bucket name
if (!bucket.validateName(callingFormat))
throw new IllegalArgumentException("Invalid Bucket Name: "+bucket);
- return generateURL(Method.PUT, bucket, "", headers);
+ return generateURI(Method.PUT, bucket, "", headers);
}
- public URL list(Bucket bucket, String prefix, String marker,
+ public URI list(Bucket bucket, String prefix, String marker,
Integer maxKeys, Headers headers){
return list(bucket, prefix, marker, maxKeys, null, headers);
}
- public URL list(Bucket bucket, String prefix, String marker,
+ public URI list(Bucket bucket, String prefix, String marker,
Integer maxKeys, String delimiter, Headers headers)
{
- return generateURL(Method.GET, bucket, headers);
+ return generateURI(Method.GET, bucket, headers);
}
- public URL delete(Bucket bucket, Headers headers)
+ public URI delete(Bucket bucket, Headers headers)
{
- return generateURL(Method.DELETE, bucket, headers);
+ return generateURI(Method.DELETE, bucket, headers);
}
- public URL put(Bucket bucket, String key, S3Object object, Headers headers) {
+ public URI put(Bucket bucket, String key, S3Object object, Headers headers) {
Headers metadata = null;
if (object != null) {
metadata = object.getMetadata();
@@ -130,63 +131,61 @@
headers = new Headers();
}
- return generateURL(Method.PUT, bucket, UrlEncoder.encode(key), headers.mergeMetadata(metadata));
+ return generateURI(Method.PUT, bucket, key, headers.mergeMetadata(metadata));
}
- public URL get(Bucket bucket, String key, Headers headers)
+ public URI get(Bucket bucket, String key, Headers headers)
{
- return generateURL(Method.GET, bucket, UrlEncoder.encode(key), headers);
+ return generateURI(Method.GET, bucket, key, headers);
}
- public URL delete(Bucket bucket, String key, Headers headers)
+ public URI delete(Bucket bucket, String key, Headers headers)
{
- return generateURL(Method.DELETE, bucket, UrlEncoder.encode(key), headers);
+ return generateURI(Method.DELETE, bucket, key, headers);
}
+
+ private Map<String, String> map(String name) {
+ HashMap<String, String> map = new HashMap<String, String>();
+ map.put(name, "");
+ return map;
+ }
- public URL getBucketLogging(Bucket bucket, Headers headers) {
- Map<String, String> pathArgs = new HashMap<String, String>();
- pathArgs.put("logging", null);
- return generateURL(Method.GET, bucket, "", pathArgs, headers);
+ public URI getBucketLogging(Bucket bucket, Headers headers) {
+ return generateURI(Method.GET, bucket, "", map("logging"), headers);
}
- public URL putBucketLogging(Bucket bucket, String loggingXMLDoc, Headers headers) {
- Map<String, String> pathArgs = new HashMap<String, String>();
- pathArgs.put("logging", null);
- return generateURL(Method.PUT, bucket, "", pathArgs, headers);
+ public URI putBucketLogging(Bucket bucket, Headers headers) {
+ return generateURI(Method.PUT, bucket, "", map("logging"), headers);
}
- public URL getACL(Bucket bucket, Headers headers) {
+ public URI getACL(Bucket bucket, Headers headers) {
return getACL(bucket, "", headers);
}
- public URL getACL(Bucket bucket, String key, Headers headers)
+ public URI getACL(Bucket bucket, String key, Headers headers)
{
- Map<String, String> pathArgs = new HashMap<String, String>();
- pathArgs.put("acl", null);
- return generateURL(Method.GET, bucket, UrlEncoder.encode(key), pathArgs, headers);
+ return generateURI(Method.GET, bucket, key, map("acl"), headers);
}
- public URL putACL(Bucket bucket, String aclXMLDoc, Headers headers) {
- return putACL(bucket, "", aclXMLDoc, headers);
+ public URI putACL(Bucket bucket, Headers headers) {
+ return putACL(bucket, "", headers);
}
- public URL putACL(Bucket bucket, String key, String aclXMLDoc, Headers headers)
+ public URI putACL(Bucket bucket, String key, Headers headers)
{
- Map<String, String> pathArgs = new HashMap<String, String>();
- pathArgs.put("acl", null);
- return generateURL(Method.PUT, bucket, UrlEncoder.encode(key), pathArgs, headers);
+ return generateURI(Method.PUT, bucket, key, map("acl"), headers);
}
- public URL listAllBuckets(Headers headers)
+ public URI listAllBuckets(Headers headers)
{
- return generateURL(Method.GET, headers);
+ return generateURI(Method.GET, headers);
}
- public URL listAllBuckets() {
+ public URI listAllBuckets() {
return listAllBuckets(null);
}
- public String makeBareURL(Bucket bucket, String key) {
+ public String makeBareURI(Bucket bucket, String key) {
StringBuilder buffer = new StringBuilder();
if (this.isSecure) {
buffer.append("https://");
@@ -200,19 +199,19 @@
}
@SuppressWarnings("unchecked")
- private URL generateURL(Method method, Bucket bucket, String key, Headers headers) {
- return generateURL(method, bucket, key, new HashMap(), headers);
+ private URI generateURI(Method method, Bucket bucket, String key, Headers headers) {
+ return generateURI(method, bucket, key, new HashMap(), headers);
}
- private URL generateURL(Method method, Bucket bucket, Headers headers) {
- return generateURL(method, bucket, "", headers);
+ private URI generateURI(Method method, Bucket bucket, Headers headers) {
+ return generateURI(method, bucket, "", headers);
}
- private URL generateURL(Method method, Headers headers) {
- return generateURL(method, null, headers);
+ private URI generateURI(Method method, Headers headers) {
+ return generateURI(method, null, headers);
}
- private URL generateURL(Method method, Bucket bucket, String key, Map<String, String> pathArgs, Headers headers)
+ private URI generateURI(Method method, Bucket bucket, String key, Map<String, String> pathArgs, Headers headers)
{
long expires = 0L;
if (this.expiresIn != null) {
@@ -226,17 +225,18 @@
// convert to seconds
expires /= 1000;
- String canonicalString = CanonicalString.make(method, bucket, key, pathArgs, headers, ""+expires);
- String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString, true);
+ String enckey = UrlEncoder.encode(key);
+ String canonicalString = CanonicalString.make(method, bucket, enckey, pathArgs, headers, ""+expires);
+ String encodedCanonical = CanonicalString.encode(this.awsSecretAccessKey, canonicalString, false);
pathArgs.put("Signature", encodedCanonical);
pathArgs.put("Expires", Long.toString(expires));
pathArgs.put("AWSAccessKeyId", this.awsAccessKeyId);
try {
- return this.callingFormat.getURL(this.isSecure, server, port, bucket, key, pathArgs);
- } catch (MalformedURLException e) {
- throw new IllegalStateException("Unable to generate URL " + e);
+ return this.callingFormat.getURI(this.isSecure, server, port, bucket, key, pathArgs);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to generate URI " + e);
}
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Response.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -10,10 +10,10 @@
package com.amazon.s3;
import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.util.HashMap;
-import java.util.Map;
+import java.io.InputStream;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpMethod;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
@@ -28,35 +28,35 @@
*/
public class Response {
- private HttpURLConnection connection;
+ private HttpMethod method;
- Response(HttpURLConnection connection) throws IOException {
- this.connection = connection;
+ Response(HttpMethod method) {
+ this.method = method;
}
/**
* Returns the HTTP response code.
*/
public int getResponseCode() throws IOException {
- return connection.getResponseCode();
+ return method.getStatusCode();
}
/**
* Returns the HTTP response message.
*/
public String getResponseMessage() throws IOException {
- return connection.getResponseMessage();
+ return method.getStatusText();
}
/**
* Returns content length of the response.
*/
public int getContentLength() {
- return connection.getContentLength();
+ return -1; // TODO
}
/**
- * Throws an IllegalStateException if not 200 OK.
+ * Throws an IllegalStateException if not 200-level OK.
*/
public void assertOk() {
if (isOk())
@@ -68,7 +68,10 @@
* Returns an HTTP header field from the response.
*/
public String getHeaderField(String field) {
- return connection.getHeaderField(field);
+ Header header = method.getResponseHeader(field);
+ if (header == null)
+ return null;
+ return header.getValue();
}
/**
@@ -76,7 +79,7 @@
* Prefer caching the return value.
*/
public Headers getHeaders() {
- return new Headers(connection.getHeaderFields());
+ return new Headers(method.getResponseHeaders());
}
/**
@@ -84,7 +87,7 @@
*/
public boolean isOk() {
try {
- int code = connection.getResponseCode();
+ int code = getResponseCode();
return code == 200 || code == 204;
} catch (IOException e) {
return false;
@@ -96,7 +99,7 @@
*/
public boolean isNotFound() {
try {
- return connection.getResponseCode() == 404;
+ return getResponseCode() == 404;
} catch (IOException e) {
return false;
}
@@ -115,30 +118,6 @@
}
}
- static Map<String, String> paramsForListOptions(String prefix,
- String marker, Integer maxKeys) {
- return paramsForListOptions(prefix, marker, maxKeys, null);
- }
-
- static Map<String, String> paramsForListOptions(String prefix,
- String marker, Integer maxKeys, String delimiter) {
-
- Map<String, String> argParams = new HashMap<String, String>();
- // these three params must be url encoded
- if (prefix != null)
- argParams.put("prefix", UrlEncoder.encode(prefix));
- if (marker != null)
- argParams.put("marker", UrlEncoder.encode(marker));
- if (delimiter != null)
- argParams.put("delimiter", UrlEncoder.encode(delimiter));
-
- if (maxKeys != null)
- argParams.put("max-keys", Integer.toString(maxKeys.intValue()));
-
- return argParams;
-
- }
-
/**
* Parses the response.
*/
@@ -162,7 +141,9 @@
};
xr.setErrorHandler(eh);
- xr.parse(new InputSource(connection.getInputStream()));
+ InputStream is = method.getResponseBodyAsStream();
+ xr.parse(new InputSource(is));
+ is.close();
} catch (SAXException e) {
throw new RuntimeException("Unexpected error parsing ListBucket xml", e);
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -40,6 +40,13 @@
public S3Object(byte[] data) {
this(data, null);
}
+
+ /**
+ * Constructs a new S3Object; data is converted to bytes.
+ */
+ public S3Object(String data) {
+ this(data.getBytes());
+ }
/**
* Returns data.
@@ -49,6 +56,13 @@
}
/**
+ * Returns the length of data.
+ */
+ public int getLength() {
+ return data.length;
+ }
+
+ /**
* Returns metadata, unmodifiable.
*/
public Headers getMetadata() {
@@ -65,5 +79,5 @@
" data.length=" + this.data.length +
" metadata=" + this.metadata + "]";
}
-
+
}
Modified: amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java
===================================================================
--- amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java 2008-02-07 20:21:24 UTC (rev 5330)
+++ amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java 2008-02-07 22:57:14 UTC (rev 5331)
@@ -9,14 +9,17 @@
// affiliates.
import java.io.IOException;
+import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
-import java.net.URL;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.junit.Before;
import org.junit.Test;
@@ -47,9 +50,9 @@
// subdomain: http://bucket.s3.amazonaws.com/key
// testing pure vanity domains (http://<vanity domain>/key) is not covered here
// but is possible with some assitional setup
- test(CallingFormat.getSubdomainCallingFormat(), Connection.LOCATION_DEFAULT, true, Connection.DEFAULT_HOST);
- test(CallingFormat.getPathCallingFormat(), Connection.LOCATION_DEFAULT, true, Connection.DEFAULT_HOST);
- test(CallingFormat.getSubdomainCallingFormat(), Connection.LOCATION_EU, true, Connection.DEFAULT_HOST);
+ test(CallingFormat.SUBDOMAIN, Connection.LOCATION_DEFAULT, false, Connection.DEFAULT_HOST);
+ test(CallingFormat.PATH, Connection.LOCATION_DEFAULT, true, Connection.DEFAULT_HOST);
+ test(CallingFormat.SUBDOMAIN, Connection.LOCATION_EU, true, Connection.DEFAULT_HOST);
}
private void test(CallingFormat format, String location, boolean secure, String server) throws Exception
@@ -63,17 +66,17 @@
new QueryGenerator(awsAccessKeyId, awsSecretAccessKey, secure, server, format);
Response response = conn.create(bucket, location, null);
- assertEquals(
- "couldn't create bucket",
- HttpURLConnection.HTTP_OK,
- response.getResponseCode());
+ response.assertOk();
- ListResponse listBucketResponse = conn.list(bucket, null, null, null, null);
- assertEquals(
- "couldn't get list",
- HttpURLConnection.HTTP_OK,
- listBucketResponse.getResponseCode());
- assertEquals("list wasn't empty", 0, listBucketResponse.getEntries().size());
+ ListResponse listBucketResponse = conn.list(bucket);
+ listBucketResponse.assertOk();
+ for (Entry entry : listBucketResponse.getEntries()) {
+ Response delete = conn.delete(bucket, entry.getKey());
+ System.out.println("DEL " + delete);
+ delete.assertOk();
+ }
+ listBucketResponse = conn.list(bucket);
+ assertEquals("list wasn't empty " + listBucketResponse, 0, listBucketResponse.getEntries().size());
System.out.println(listBucketResponse);
verifyBucketResponseParameters(listBucketResponse, bucket, "", "", UnspecifiedMaxKeys, null, false, null);
@@ -84,79 +87,54 @@
final String innerKey = "test/inner.txt";
final String lastKey = "z-last-key.txt";
- response = conn.put(bucket, key, new S3Object(text.getBytes()));
- assertEquals(
- "couldn't put simple object",
- HttpURLConnection.HTTP_OK,
- response.getResponseCode());
+ response = conn.put(bucket, key, new S3Object(text));
+ response.assertOk();
- response = conn.put(bucket, innerKey, new S3Object(text.getBytes()), null);
- assertEquals(
- "couldn't put simple object",
- HttpURLConnection.HTTP_OK,
- response.getResponseCode());
+ response = conn.put(bucket, innerKey, new S3Object(text));
+ response.assertOk();
- response = conn.put(bucket, lastKey, new S3Object(text.getBytes()), null);
- assertEquals(
- "couldn't put simple object",
- HttpURLConnection.HTTP_OK,
- response.getResponseCode());
+ response = conn.put(bucket, lastKey, new S3Object(text));
+ response.assertOk();
// plain list
- listBucketResponse = conn.list(bucket, null, null, null, null);
- assertEquals(
- "couldn't get list",
- listBucketResponse.getResponseCode(),
- HttpURLConnection.HTTP_OK);
+ listBucketResponse = conn.list(bucket);
+ listBucketResponse.assertOk();
assertEquals("Unexpected list size", 3, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 0, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "", "", UnspecifiedMaxKeys, null, false, null);
+
+ System.out.println("LIST " + listBucketResponse.getEntries());
// root "directory"
listBucketResponse = conn.list(bucket, null, null, null, "/", null);
- assertEquals(
- "couldn't get list",
- HttpURLConnection.HTTP_OK,
- listBucketResponse.getResponseCode());
- assertEquals("Unexpected list size", 2, listBucketResponse.getEntries().size());
+ listBucketResponse.assertOk();
+ assertEquals("Unexpected list size " + listBucketResponse, 2, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 1, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "", "", UnspecifiedMaxKeys, "/", false, null);
// root "directory" with a max-keys of "1"
listBucketResponse = conn.list(bucket, null, null, 1, "/", null);
- assertEquals(
- "couldn't get list",
- HttpURLConnection.HTTP_OK,
- listBucketResponse.getResponseCode());
+ listBucketResponse.assertOk();
assertEquals("Unexpected list size", 1, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 0, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "", "", 1, "/", true, "example.txt");
// root "directory" with a max-keys of "2"
listBucketResponse = conn.list(bucket, null, null, 2, "/", null);
- assertEquals(
- "couldn't get list",
- HttpURLConnection.HTTP_OK,
- listBucketResponse.getResponseCode());
+ listBucketResponse.assertOk();
assertEquals("Unexpected list size", 1, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 1, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "", "", 2, "/", true, "test/");
String marker = listBucketResponse.getNextMarker();
listBucketResponse = conn.list(bucket, null, marker, new Integer( 2 ), "/", null);
- assertEquals(
- "couldn't get list",
- HttpURLConnection.HTTP_OK,
- listBucketResponse.getResponseCode());
+ listBucketResponse.assertOk();
assertEquals("Unexpected list size", 1, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 0, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "", marker, 2, "/", false, null);
// test "directory"
listBucketResponse = conn.list(bucket, "test/", null, null, "/", null);
- assertEquals(
- "couldn't get list",
- HttpURLConnection.HTTP_OK,
- listBucketResponse.getResponseCode());
+ listBucketResponse.assertOk();
assertEquals("Unexpected list size", 1, listBucketResponse.getEntries().size());
assertEquals("Unexpected common prefix size", 0, listBucketResponse.getCommonPrefixEntries().size());
verifyBucketResponseParameters(listBucketResponse, bucket, "test/", "", UnspecifiedMaxKeys, "/", false, null);
@@ -179,24 +157,15 @@
// end delimiter tests
response = conn.put(bucket, key, new S3Object(text.getBytes(), null), null);
- assertEquals(
- "couldn't reput simple object",
- HttpURLConnection.HTTP_OK,
- response.getResponseCode());
+ response.assertOk();
- Map<String, List<String>> metadata = new HashMap<String, List<String>>();
- metadata.put("title", Arrays.asList(new String[] { "title" }));
- response = conn.put(bucket, key, new S3Object(text.getBytes(), new Headers(metadata)), null);
- assertEquals(
- "couldn't put complex object",
- HttpURLConnection.HTTP_OK,
- response.getResponseCode());
+ Headers metadata = new Headers();
+ metadata.put("title", "title");
+ response = conn.put(bucket, key, new S3Object(text.getBytes(), metadata), null);
+ response.assertOk();
GetResponse getResponse = conn.get(bucket, key, null);
- assertEquals(
- "couldn't get object",
- getResponse.getResponseCode(),
- HttpURLConnection.HTTP_OK);
+ getResponse.assertOk();
assertEquals("didn't get the right data back", text.getBytes(), getResponse.getObject().getData());
assertEquals("didn't get the right metadata back", 1, getResponse.getObject().getMetadata().size());
assertEquals(
@@ -207,8 +176,14 @@
"didn't get the right content-length",
""+text.length(),
getResponse.getHeaderField("Content-Length"));
+
+ GetStreamResponse streamResponse = conn.getStream(bucket, key);
+ InputStream is = streamResponse.getInputStream();
+ byte b[] = new byte[text.length()];
+ int len = is.read(b);
+ assertEquals("didn't get the right data back " + len, text.getBytes(), b);
+ streamResponse.release();
-
String titleWithSpaces = " \t title with leading and trailing spaces ";
Headers h = new Headers();
h.put("title", titleWithSpaces);
@@ -345,73 +320,73 @@
buckets.size() - 1,
listAllMyBucketsResponse.getEntries().size());
- checkURL(
+ checkURI(
generator.create(bucket, null),
- "PUT",
+ Method.PUT,
HttpURLConnection.HTTP_OK,
"couldn't create bucket");
- checkURL(
+ checkURI(
generator.put(bucket, key, new S3Object("test data".getBytes(), null), null),
- "PUT",
+ Method.PUT,
HttpURLConnection.HTTP_OK,
"put object",
"test data");
- checkURL(
+ checkURI(
generator.get(bucket, key, null),
- "GET",
+ Method.GET,
HttpURLConnection.HTTP_OK,
"get object");
- checkURL(
+ checkURI(
generator.list(bucket, null, null, null, null),
- "GET",
+ Method.GET,
HttpURLConnection.HTTP_OK,
"list bucket");
- checkURL(
+ checkURI(
generator.listAllBuckets(),
- "GET",
+ Method.GET,
HttpURLConnection.HTTP_OK,
"list all my buckets");
- checkURL(
+ checkURI(
generator.getACL(bucket, key, null),
- "GET",
+ Method.GET,
HttpURLConnection.HTTP_OK,
"get acl");
- checkURL(
- generator.putACL(bucket, key, new String(acl), null),
- "PUT",
+ checkURI(
+ generator.putACL(bucket, key, null),
+ Method.PUT,
HttpURLConnection.HTTP_OK,
"put acl",
new String(acl));
- checkURL(
+ checkURI(
generator.getACL(bucket, null),
- "GET",
+ Method.GET,
HttpURLConnection.HTTP_OK,
"get bucket acl");
- checkURL(
- generator.putACL(bucket, new String(bucketACL), null),
- "PUT",
+ checkURI(
+ generator.putACL(bucket, null),
+ Method.PUT,
HttpURLConnection.HTTP_OK,
"put bucket acl",
new String(bucketACL));
- checkURL(
+ checkURI(
generator.getBucketLogging(bucket, null),
- "GET",
+ Method.GET,
HttpURLConnection.HTTP_OK,
"get bucket logging");
- checkURL(
- generator.putBucketLogging(bucket, new String(bucketLogging), null),
- "PUT",
+ checkURI(
+ generator.putBucketLogging(bucket, null),
+ Method.PUT,
HttpURLConnection.HTTP_OK,
"put bucket logging",
new String(bucketLogging));
- checkURL(
+ checkURI(
generator.delete(bucket, key, null),
- "DELETE",
+ Method.DELETE,
HttpURLConnection.HTTP_NO_CONTENT,
"delete object");
- checkURL(
+ checkURI(
generator.delete(bucket, null),
- "DELETE",
+ Method.DELETE,
HttpURLConnection.HTTP_NO_CONTENT,
"delete bucket");
}
@@ -461,29 +436,27 @@
}
}
- private static void checkURL(URL url, String method, int code, String message)
+ private static void checkURI(URI uri, Method method, int code, String message)
throws MalformedURLException, IOException
{
- checkURL(url, method, code, message, null);
+ checkURI(uri, method, code, message, null);
}
- private static void checkURL(URL url, String method, int code, String message, String data)
+ private static void checkURI(URI uri, Method method, int code, String message, String data)
throws MalformedURLException, IOException
{
if (data == null) data = "";
- HttpURLConnection connection = (HttpURLConnection)url.openConnection();
- connection.setRequestMethod(method);
- if ("PUT".equals(method)) {
- connection.setRequestProperty("Content-Length", ""+data.getBytes().length);
- connection.setDoOutput(true);
- connection.getOutputStream().write(data.getBytes());
- } else {
- // HttpURLConnection auto populates Content-Type, which we don't want here
- connection.setRequestProperty("Content-Type", "");
+ HttpClient client = new HttpClient();
+ HttpMethod httpMethod = method.createHttpMethod();
+ if (method == Method.PUT) {
+ ((EntityEnclosingMethod) httpMethod).setRequestEntity(new StringRequestEntity(data));
}
+ httpMethod.setURI(uri);
+ int response = client.executeMethod(httpMethod);
+ httpMethod.releaseConnection();
- assertEquals(message, code, connection.getResponseCode());
+ assertEquals(message, code, response);
}
private void readline() throws IOException {
@@ -546,7 +519,7 @@
readline();
System.out.println("\nNow try just the url without the query string arguments. It should fail.\n");
- System.out.println(generator.makeBareURL(bucket, keyName));
+ System.out.println(generator.makeBareURI(bucket, keyName));
System.out.print("\npress enter> ");
readline();
@@ -566,14 +539,14 @@
System.out.println("----- anonymous read test -----");
System.out.println("\nYou should be able to try this in your browser\n");
- System.out.println(generator.makeBareURL(bucket, keyName + "-public"));
+ System.out.println(generator.makeBareURI(bucket, keyName + "-public"));
System.out.print("\npress enter> ");
readline();
System.out.println("----- path style url example -----");
System.out.println("\nNon-location-constrained buckets can also be specified as part of the url path. (This was the original url style supported by S3.)");
System.out.println("\nTry this url out in your browser (it will only be valid for 60 seconds)\n");
- generator.setCallingFormat(CallingFormat.getPathCallingFormat());
+ generator.setCallingFormat(CallingFormat.PATH);
// could also have been done like this:
// generator = new QueryStringAuthGenerator(awsAccessKeyId, awsSecretAccessKey, true, Utils.DEFAULT_HOST, CallingFormat.getPathCallingFormat());
generator.setExpiresIn(60 * 1000);
Added: amazon-s3/trunk/src/test/resources/log4j.xml
===================================================================
--- amazon-s3/trunk/src/test/resources/log4j.xml (rev 0)
+++ amazon-s3/trunk/src/test/resources/log4j.xml 2008-02-07 22:57:14 UTC (rev 5331)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<!-- $Id: log4j.xml,v 1.2 2008/01/24 17:52:51 rosse Exp $ -->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+ <!-- ============================== -->
+ <!-- Append messages to the console -->
+ <!-- ============================== -->
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <!-- The default pattern: Date Priority [Category] Message\n -->
+ <param name="ConversionPattern" value="%r %-5p [%c{1}] (%t) %m%n"/>
+ </layout>
+ </appender>
+
+ <logger name="org.apache">
+ <level value="INFO"/>
+ </logger>
+ <logger name="httpclient.wire">
+ <level value="INFO"/>
+ </logger>
+ <logger name="org.apache.commons.httpclient">
+ <level value="INFO"/>
+ </logger>
+
+ <!-- ======================= -->
+ <!-- Setup the Root category -->
+ <!-- ======================= -->
+
+ <root>
+ <priority value="INFO"/>
+ <appender-ref ref="CONSOLE"/>
+ </root>
+
+</log4j:configuration>
17 years, 8 months
JBoss Cache SVN: r5330 - in core/trunk/src/main/java/org/jboss/cache: config and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-07 15:21:24 -0500 (Thu, 07 Feb 2008)
New Revision: 5330
Modified:
core/trunk/src/main/java/org/jboss/cache/RegionManager.java
core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java
Log:
[JBAS-1288] Avoid duplicate default region configs
Modified: core/trunk/src/main/java/org/jboss/cache/RegionManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionManager.java 2008-02-07 20:19:51 UTC (rev 5329)
+++ core/trunk/src/main/java/org/jboss/cache/RegionManager.java 2008-02-07 20:21:24 UTC (rev 5330)
@@ -809,9 +809,45 @@
public void setEvictionConfig(EvictionConfig evictionConfig)
{
this.evictionConfig = evictionConfig;
+
+ // JBAS-1288
+ // Try to establish a default region if there isn't one already
+ boolean needDefault = true;
+ List<EvictionRegionConfig> ercs = evictionConfig.getEvictionRegionConfigs();
+
+ // APPROACH 1: Scan for a default region, try to add if not there.
+ // This will try to add the region if it is missing but seems to break
+ // some unit tests that configure one or more non-default regions and
+ // no default region (e.g. the eviction.minttl tests). So, doing this
+ // seems to add a new semantic. For now comment this out and use APPROACH 2
+// for (EvictionRegionConfig erc : ercs)
+// {
+// if (DEFAULT_REGION.equals(erc.getRegionFqn()))
+// {
+// needDefault = false;
+// break;
+// }
+// }
+ // APPROACH 2: Only add a default region if there are no regions. This is
+ // contrary to the idea that there *must* be a default region, but some
+ // unit tests fail w/ APPROACH 1, so for now we go with this approach.
+ needDefault = ercs.size() == 0;
+
+ if (needDefault)
+ {
+ // This may throw ConfigurationException if there is no default
+ // eviction policy class
+ EvictionRegionConfig dflt = evictionConfig.createDefaultEvictionRegionConfig();
+ ercs.add(0, dflt); // put it first
+ // Need to pass this back into the evictionConfig so it knows
+ // about the new region
+ evictionConfig.setEvictionRegionConfigs(ercs);
+ }
+
+ // create regions for the regions defined in the evictionConfig.
+ // scan to be sure the _default_ region isn't added twice
boolean setDefault = false;
- // create regions for the regions defined in the evictionConfig.
- for (EvictionRegionConfig erc : evictionConfig.getEvictionRegionConfigs())
+ for (EvictionRegionConfig erc : ercs)
{
Fqn fqn = erc.getRegionFqn();
if (log.isTraceEnabled()) log.trace("Creating eviction region " + fqn);
Modified: core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java 2008-02-07 20:19:51 UTC (rev 5329)
+++ core/trunk/src/main/java/org/jboss/cache/config/EvictionConfig.java 2008-02-07 20:21:24 UTC (rev 5330)
@@ -21,12 +21,14 @@
*/
package org.jboss.cache.config;
+import org.jboss.cache.Fqn;
import org.jboss.cache.RegionManager;
import org.jboss.cache.eviction.EvictionPolicy;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class EvictionConfig extends ConfigurationComponent
{
@@ -80,28 +82,55 @@
testImmutability("defaultEvictionPolicyClass");
this.defaultEvictionPolicyClass = defaultEvictionPolicyClass;
}
-
- public List<EvictionRegionConfig> getEvictionRegionConfigs()
+
+ /**
+ * Creates an EvictionRegionConfig for the
+ * {@link RegionManager.DEFAULT_REGION "_default_"} region using the
+ * {@link #getDefaultEvictionPolicyClass(String) default eviction policy class}. Throws a
+ * {@link ConfigurationException} if
+ * {@link #setDefaultEvictionPolicyClass(String) a default eviction policy class}
+ * has not been set.
+ *
+ * @return an EvictionRegionConfig whose FQN is {@link RegionManager.DEFAULT_REGION}
+ * and whose EvictionPolicyConfig is the default config for the
+ * default eviction policy class.
+ *
+ * @throws ConfigurationException if a
+ * {@link #setDefaultEvictionPolicyClass(String) a default eviction policy class}
+ * has not been set or there is a problem instantiating the configuration.
+ */
+ public EvictionRegionConfig createDefaultEvictionRegionConfig()
{
- if (evictionRegionConfigs == null && defaultEvictionPolicyClass != null)
+ if (defaultEvictionPolicyClass != null)
{
- // TODO this needs to be refactored obviously ...
try
{
Class<?> cpolicy = Class.forName(defaultEvictionPolicyClass);
EvictionPolicy policy = (EvictionPolicy) cpolicy.newInstance();
EvictionRegionConfig erc = new EvictionRegionConfig();
EvictionPolicyConfig epc = policy.getEvictionConfigurationClass().newInstance();
- // epc.set
erc.setEvictionPolicyConfig(epc);
erc.setRegionFqn(RegionManager.DEFAULT_REGION);
- return Collections.singletonList(erc);
+ return erc;
}
catch (Exception e)
{
- throw new ConfigurationException(e);
+ log.error("Unable to create EvictionRegionConfig for default region", e);
+ throw new ConfigurationException("Unable to create EvictionRegionConfig for default region", e);
}
}
+ else
+ {
+ throw new ConfigurationException("Cannot create EvictionRegionConfig for default region; no defaultEvictionPolicyClass configured");
+ }
+ }
+
+ public List<EvictionRegionConfig> getEvictionRegionConfigs()
+ {
+ if (evictionRegionConfigs == null)
+ {
+ return new ArrayList<EvictionRegionConfig>(1);
+ }
return evictionRegionConfigs;
}
17 years, 8 months
JBoss Cache SVN: r5329 - in core/trunk/src/test/java/org/jboss/cache: invalidation and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-07 15:19:51 -0500 (Thu, 07 Feb 2008)
New Revision: 5329
Modified:
core/trunk/src/test/java/org/jboss/cache/eviction/minttl/MinTTLTestBase.java
core/trunk/src/test/java/org/jboss/cache/invalidation/TombstoneEvictionTest.java
Log:
Don't use an immutable list
Modified: core/trunk/src/test/java/org/jboss/cache/eviction/minttl/MinTTLTestBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/eviction/minttl/MinTTLTestBase.java 2008-02-07 19:16:39 UTC (rev 5328)
+++ core/trunk/src/test/java/org/jboss/cache/eviction/minttl/MinTTLTestBase.java 2008-02-07 20:19:51 UTC (rev 5329)
@@ -11,6 +11,7 @@
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -49,7 +50,8 @@
regionCfg.setEvictionPolicyConfig(cfg);
// set regions in a list
- List<EvictionRegionConfig> evictionRegionConfigs = Collections.singletonList(regionCfg);
+ List<EvictionRegionConfig> evictionRegionConfigs = new ArrayList<EvictionRegionConfig>();
+ evictionRegionConfigs.add(regionCfg);
// cache-wide
EvictionConfig ec = new EvictionConfig();
Modified: core/trunk/src/test/java/org/jboss/cache/invalidation/TombstoneEvictionTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/invalidation/TombstoneEvictionTest.java 2008-02-07 19:16:39 UTC (rev 5328)
+++ core/trunk/src/test/java/org/jboss/cache/invalidation/TombstoneEvictionTest.java 2008-02-07 20:19:51 UTC (rev 5329)
@@ -13,6 +13,7 @@
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -47,7 +48,8 @@
regionCfg.setEvictionPolicyConfig(cfg);
// set regions in a list
- List<EvictionRegionConfig> evictionRegionConfigs = Collections.singletonList(regionCfg);
+ List<EvictionRegionConfig> evictionRegionConfigs = new ArrayList<EvictionRegionConfig>();
+ evictionRegionConfigs.add(regionCfg);
EvictionConfig ec = new EvictionConfig();
17 years, 8 months
JBoss Cache SVN: r5328 - core/trunk/src/test/java/org/jboss/cache/config.
by jbosscache-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-07 14:16:39 -0500 (Thu, 07 Feb 2008)
New Revision: 5328
Modified:
core/trunk/src/test/java/org/jboss/cache/config/EvictionRegionConfigurationTest.java
Log:
No need to set the region name
Modified: core/trunk/src/test/java/org/jboss/cache/config/EvictionRegionConfigurationTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/config/EvictionRegionConfigurationTest.java 2008-02-07 18:29:47 UTC (rev 5327)
+++ core/trunk/src/test/java/org/jboss/cache/config/EvictionRegionConfigurationTest.java 2008-02-07 19:16:39 UTC (rev 5328)
@@ -41,7 +41,6 @@
EvictionRegionConfig erc = new EvictionRegionConfig();
erc.setRegionFqn(RegionManager.DEFAULT_REGION);
- erc.setRegionName("_default_");
EvictionPolicy policy = LRUPolicy.class.newInstance();
erc.setEvictionPolicyConfig(policy.getEvictionConfigurationClass().newInstance());
17 years, 8 months