Modified: ode/trunk/dao-hibernate/src/main/java/org/apache/ode/daohib/bpel/CorrelatorDaoImpl.java URL: http://svn.apache.org/viewvc/ode/trunk/dao-hibernate/src/main/java/org/apache/ode/daohib/bpel/CorrelatorDaoImpl.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/dao-hibernate/src/main/java/org/apache/ode/daohib/bpel/CorrelatorDaoImpl.java (original) +++ ode/trunk/dao-hibernate/src/main/java/org/apache/ode/daohib/bpel/CorrelatorDaoImpl.java Thu Jun 5 14:14:08 2008 @@ -25,7 +25,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.common.CorrelationKey; -import org.apache.ode.bpel.common.ProcessState; import org.apache.ode.bpel.dao.CorrelatorDAO; import org.apache.ode.bpel.dao.MessageExchangeDAO; import org.apache.ode.bpel.dao.MessageRouteDAO; @@ -36,7 +35,7 @@ import org.apache.ode.daohib.bpel.hobj.HCorrelatorSelector; import org.apache.ode.daohib.bpel.hobj.HMessageExchange; import org.apache.ode.daohib.bpel.hobj.HProcessInstance; -import org.apache.ode.utils.ArrayUtils; +import org.apache.ode.utils.CollectionUtils; import org.hibernate.Hibernate; import org.hibernate.LockMode; import org.hibernate.Query; @@ -147,7 +146,7 @@ public void enqueueMessage(MessageExchangeDAO mex, CorrelationKey[] correlationKeys) { String[] keys = canonifyKeys(correlationKeys); String hdr = "enqueueMessage(mex=" + ((MessageExchangeDaoImpl) mex)._hobj.getId() + " keys=" - + ArrayUtils.makeCollection(ArrayList.class, keys) + "): "; + + CollectionUtils.makeCollection(ArrayList.class, keys) + "): "; if (__log.isDebugEnabled()) __log.debug(hdr);
Modified: ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.java URL: http://svn.apache.org/viewvc/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.java (original) +++ ode/trunk/jacob/src/main/java/org/apache/ode/jacob/JacobRunnable.java Thu Jun 5 14:14:08 2008 @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.Set; -import org.apache.ode.utils.ArrayUtils; +import org.apache.ode.utils.CollectionUtils; /** * Base class for process abstractions. An abstraction is a parameterized @@ -71,7 +71,7 @@ static { try { - Method m = JacobRunnable.class.getMethod("run", ArrayUtils.EMPTY_CLASS_ARRAY); + Method m = JacobRunnable.class.getMethod("run", CollectionUtils.EMPTY_CLASS_ARRAY); IMPLEMENTED_METHODS = Collections.singleton(m); } catch (NoSuchMethodException e) { throw new AssertionError(e); Modified: ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ChannelFactory.java URL: http://svn.apache.org/viewvc/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ChannelFactory.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ChannelFactory.java (original) +++ ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ChannelFactory.java Thu Jun 5 14:14:08 2008 @@ -24,7 +24,7 @@ import org.apache.ode.jacob.Channel; import org.apache.ode.jacob.soup.CommChannel; -import org.apache.ode.utils.ArrayUtils; +import org.apache.ode.utils.CollectionUtils; public class ChannelFactory { private static final Method METHOD_OBJECT_EQUALS; @@ -39,7 +39,7 @@ } try { - METHOD_CHANNEL_EXPORT = Channel.class.getMethod("export", ArrayUtils.EMPTY_CLASS_ARRAY); + METHOD_CHANNEL_EXPORT = Channel.class.getMethod("export", CollectionUtils.EMPTY_CLASS_ARRAY); } catch (Exception e) { throw new AssertionError("No export() method on Object!"); } Modified: ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ExecutionQueueImpl.java URL: http://svn.apache.org/viewvc/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ExecutionQueueImpl.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ExecutionQueueImpl.java (original) +++ ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/ExecutionQueueImpl.java Thu Jun 5 14:14:08 2008 @@ -33,7 +33,7 @@ import org.apache.ode.jacob.soup.ExecutionQueue; import org.apache.ode.jacob.soup.ExecutionQueueObject; import org.apache.ode.jacob.soup.ReplacementMap; -import org.apache.ode.utils.ArrayUtils; +import org.apache.ode.utils.CollectionUtils; import org.apache.ode.utils.ObjectPrinter; import java.io.Externalizable; @@ -142,7 +142,7 @@ public Continuation dequeueReaction() { if (__log.isTraceEnabled()) { - __log.trace(ObjectPrinter.stringifyMethodEnter("dequeueReaction", ArrayUtils.EMPTY_OBJECT_ARRAY)); + __log.trace(ObjectPrinter.stringifyMethodEnter("dequeueReaction", CollectionUtils.EMPTY_OBJECT_ARRAY)); } Continuation continuation = null; @@ -209,7 +209,7 @@ public int cycle() { if (__log.isTraceEnabled()) { - __log.trace(ObjectPrinter.stringifyMethodEnter("cycle", ArrayUtils.EMPTY_OBJECT_ARRAY)); + __log.trace(ObjectPrinter.stringifyMethodEnter("cycle", CollectionUtils.EMPTY_OBJECT_ARRAY)); } return ++_currentCycle; @@ -243,7 +243,7 @@ public void flush() { if (__log.isTraceEnabled()) { - __log.trace(ObjectPrinter.stringifyMethodEnter("flush", ArrayUtils.EMPTY_OBJECT_ARRAY)); + __log.trace(ObjectPrinter.stringifyMethodEnter("flush", CollectionUtils.EMPTY_OBJECT_ARRAY)); } } @@ -622,7 +622,7 @@ public MessageFrame(CommGroupFrame commFrame, ChannelFrame channelFrame, String method, Object[] args) { super(commFrame, channelFrame); this.method = method; - this.args = args == null ? ArrayUtils.EMPTY_CLASS_ARRAY : args; + this.args = args == null ? CollectionUtils.EMPTY_CLASS_ARRAY : args; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { Modified: ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/JacobVPU.java URL: http://svn.apache.org/viewvc/ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/JacobVPU.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/JacobVPU.java (original) +++ ode/trunk/jacob/src/main/java/org/apache/ode/jacob/vpu/JacobVPU.java Thu Jun 5 14:14:08 2008 @@ -22,7 +22,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.ode.jacob.*; import org.apache.ode.jacob.soup.*; -import org.apache.ode.utils.ArrayUtils; +import org.apache.ode.utils.CollectionUtils; import org.apache.ode.utils.ObjectPrinter; import org.apache.ode.utils.msg.MessageBundle; @@ -57,7 +57,7 @@ */ static { try { - REDUCE_METHOD = JacobRunnable.class.getMethod("run", ArrayUtils.EMPTY_CLASS_ARRAY); + REDUCE_METHOD = JacobRunnable.class.getMethod("run", CollectionUtils.EMPTY_CLASS_ARRAY); } catch (Exception e) { throw new Error("Cannot resolve 'run' method", e); } @@ -118,7 +118,7 @@ */ public boolean execute() { if (__log.isTraceEnabled()) { - __log.trace(ObjectPrinter.stringifyMethodEnter("execute", ArrayUtils.EMPTY_OBJECT_ARRAY)); + __log.trace(ObjectPrinter.stringifyMethodEnter("execute", CollectionUtils.EMPTY_OBJECT_ARRAY)); } if (_executionQueue == null) { throw new IllegalStateException("No state object for VPU!"); @@ -151,7 +151,7 @@ public void flush() { if (__log.isTraceEnabled()) { - __log.trace(ObjectPrinter.stringifyMethodEnter("flush", ArrayUtils.EMPTY_OBJECT_ARRAY)); + __log.trace(ObjectPrinter.stringifyMethodEnter("flush", CollectionUtils.EMPTY_OBJECT_ARRAY)); } _executionQueue.flush(); } @@ -214,7 +214,7 @@ if (__log.isDebugEnabled()) { __log.debug("injecting " + concretion); } - addReaction(concretion, REDUCE_METHOD, ArrayUtils.EMPTY_OBJECT_ARRAY, + addReaction(concretion, REDUCE_METHOD, CollectionUtils.EMPTY_OBJECT_ARRAY, (__log.isInfoEnabled() ? concretion.toString() : null)); } @@ -313,7 +313,7 @@ desc = template.toString(); } _statistics.numReductionsStruct++; - addReaction(template, REDUCE_METHOD, ArrayUtils.EMPTY_OBJECT_ARRAY, desc); + addReaction(template, REDUCE_METHOD, CollectionUtils.EMPTY_OBJECT_ARRAY, desc); } public Channel message(Channel channel, Method method, Object[] args) { Added: ode/trunk/utils/src/main/java/org/apache/ode/utils/CollectionUtils.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/main/java/org/apache/ode/utils/CollectionUtils.java?rev=663741&view=auto ============================================================================== --- ode/trunk/utils/src/main/java/org/apache/ode/utils/CollectionUtils.java (added) +++ ode/trunk/utils/src/main/java/org/apache/ode/utils/CollectionUtils.java Thu Jun 5 14:14:08 2008 @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.ode.utils; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +/** + * Utility class for dealing with arrays. + */ +public class CollectionUtils { + + public static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{}; + public static final Class[] EMPTY_CLASS_ARRAY = new Class[]{}; + + /** + * Make a [EMAIL PROTECTED] Collection} out of an array. + * + * @param type the type of [EMAIL PROTECTED] Collection} to make. + * @param elements objects to put into the collection. + * @return a [EMAIL PROTECTED] Collection} of the type given in the <code>type</type> argument containing <code>elements</code> + */ + @SuppressWarnings("unchecked") + public static <T> Collection<T> makeCollection(Class<? extends Collection> type, T[] elements) { + if (elements == null) { + return null; + } + try { + Collection<T> c = type.newInstance(); + + for (int i = 0; i < elements.length; ++i) { + c.add(elements[i]); + } + + return c; + } catch (Exception ex) { + throw new IllegalArgumentException("Invalid arguments.", ex); + } + } + + /** + * Compares the two specified maps for equality. Returns + * <tt>true</tt> if the two maps represent the same mappings. More formally, two maps <tt>m1</tt> and + * <tt>m2</tt> represent the same mappings if + * <tt>m1.keySet().equals(m2.keySet())</tt> and for every key <tt>k</tt> + * in <tt>m1.keySet()</tt>, <tt> (m1.get(k)==null ? m2.get(k)==null : + * m1.get(k).equals(m2.get(k))) </tt>. + * <p/> + * This implementation first checks if the <tt>m1</tt> and <tt>m2</tt> are the same object; + * if so it returns <tt>true</tt>. Then, it checks if the two maps have the same sizw; if + * not, it returns <tt>false</tt>. If so, it iterates over <tt>m1</tt>'s + * <tt>entrySet</tt> collection, and checks that map <tt>m1</tt> + * contains each mapping that map <tt>m2</tt> contains. If map <tt>m1</tt> + * fails to contain such a mapping, <tt>false</tt> is returned. If the + * iteration completes, <tt>true</tt> is returned. + * + * @return <tt>true</tt> if the specified object is equal to this map. + */ + public static boolean equals(Map m1, Map m2) { + if (m2 == m1) return true; + if (m1 == null) return false; + if (m2 == null) return false; + if (m2.size() != m1.size()) return false; + + try { + for (Iterator it = m1.entrySet().iterator(); it.hasNext();) { + Map.Entry e = (Map.Entry) it.next(); + Object key = e.getKey(); + Object value = e.getValue(); + if (value == null) { + if (!(m2.get(key) == null && m2.containsKey(key))) + return false; + } else { + if (!value.equals(m2.get(key))) + return false; + } + } + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + return true; + } + +} Added: ode/trunk/utils/src/main/java/org/apache/ode/utils/HierarchiedProperties.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/main/java/org/apache/ode/utils/HierarchiedProperties.java?rev=663741&view=auto ============================================================================== --- ode/trunk/utils/src/main/java/org/apache/ode/utils/HierarchiedProperties.java (added) +++ ode/trunk/utils/src/main/java/org/apache/ode/utils/HierarchiedProperties.java Thu Jun 5 14:14:08 2008 @@ -0,0 +1,433 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ode.utils; + +import org.apache.commons.collections.map.MultiKeyMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.Collections; + +/** + * This class load a regular property file in [EMAIL PROTECTED] java.util.Properties} instance. The main feature is that property can + * be hierarchied/chained in three levels. Then when querying for a property, if it's not found in the deepest level, + * the parent will be queryed and so on. + * <p/> + * A prefix must be defined to discriminate the property name and the level-1, level-2 names. The default prefix is [EMAIL PROTECTED] #ODE_PREFFIX}. + * <p/> + * Properties must respect the following pattern: [level1[.level2].prefix.]property + * <p/> + * A concrete use case could be the definition of properties for wsdl services and ports. + * <br/>Level 0 would be: values common to all services and ports. + * <br/>Level 1: values common to a given service. + * <br/>Level 2: values common to a given port. + * <p/> + * For instance, if the property file looks like this: + * <pre> + * timeout=40000 + * film-service.port-of-cannes.ode.timeout=50000 + * <p/> + * max-redirects=30 + * brel-service.ode.max-redirects=40 + * brel-service.port-of-amsterdam.ode.max-redirects=60 + * </pre> + * The following values may be expected: + * <pre> + * getProperty("max-redirects") => 30 + * getProperty("brel-service", "max-redirects") => 40 + * getProperty("brel-service", "port-of-amsterdam", "max-redirects") => 60 + * <p/> + * getProperty("film-service", "timeout") => 40000 + * getProperty("film-service", "port-of-cannes", "timeout") => 50000 + * getProperty("brel-service", "port-of-amsterdam", "timeout") => 40000 + * </pre> + * <p/> + * Values may contain some environment variables. For instance, message=You're using ${java.version}. + * <p/> + * This class is not thread-safe. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Alexis Midon</a> + */ +public class HierarchiedProperties { + + private static final Log log = LogFactory.getLog(HierarchiedProperties.class); + + // Prefix used by all properties + public static final String ODE_PREFFIX = "ode."; + + // the raw properties as of loaded from the filesystem + private Properties props = new Properties(); + private File file; + private String prefix; + /* + This map contains ChainedMap instances hierarchied according to the service and/or port they are associated with. + All ChainedMap instances has a common parent. + The ChainedMap instances are chained to each others so that if a property is not found for [service, port], + the ChainedMap associated to [service] will be queried, and if still not found, then the common parent. + + The ChainedMap instance common to all services and ports is associated to the [null, null] key. + ChainedMap instance common to all ports of a given service is associated to [service, null]. + ChainedMap instance of a given service, port couple is associated to [service, port]. + + The ChainedMap instances contain string values as loaded from the filesystem. + */ + private MultiKeyMap hierarchiedMap = new MultiKeyMap(); + + // map used to cache immutable versions of the maps + private transient MultiKeyMap cacheOfImmutableMaps = new MultiKeyMap(); + + /** + * @param file the property file to be loaded. The file may not exist. + * But if the file exists it has to be a file (not a directory), otherwhise an IOException is thrown. + * @param prefix the property prefix + * @throws IOException + */ + public HierarchiedProperties(File file, String prefix) throws IOException { + this.file = file; + this.prefix = prefix; + loadFile(); + } + + public HierarchiedProperties(File file) throws IOException { + this(file, ODE_PREFFIX); + } + + /** + * Clear all existing content, read the file and parse each property. Simply logs a message and returns if the file does not exist. + * + * @throws IOException if the file is a Directory + */ + public void loadFile() throws IOException { + if (!file.exists()) { + if (log.isDebugEnabled()) log.debug("File does not exist [" + file + "] Properties will be empty."); + return; + } + // #1. clear all existing content + clear(); + + // #2. read the file + FileInputStream fis = new FileInputStream(file); + try { + if (log.isDebugEnabled()) log.debug("Loading property file: " + file); + props.load(fis); + } finally { + fis.close(); + } + + // #3. put the root map + hierarchiedMap.put(null, null, new ChainedMap()); + + // #4. process each property + for (Object key : props.keySet()) { + String value = (String) props.get(key); + + // replace any env variables by its value + value = SystemUtils.replaceSystemProperties(value); + props.put(key, value); + + // parse the property name + String[] info = parseProperty((String) key); + String service = info[0]; + String port = info[1]; + String targetedProperty = info[2]; + + // get the map associated to this port + ChainedMap p = (ChainedMap) hierarchiedMap.get(service, port); + if (p == null) { + // create it if necessary + // get the associated service map + ChainedMap s = (ChainedMap) hierarchiedMap.get(service, null); + if (s == null) { + // create the service map if necessary, the parent is the root map. + s = new ChainedMap(getRootMap()); + // put it in the multi-map + hierarchiedMap.put(service, null, s); + } + + // create the map itself and link it to theservice map + p = new ChainedMap(s); + // put it in the multi-map + hierarchiedMap.put(service, port, p); + } + + // save the key/value in its chained map + p.put(targetedProperty, value); + } + } + + /** + * Clear all content. If [EMAIL PROTECTED] #loadFile()} is not invoked later, all returned values will be null. + */ + public void clear() { + props.clear(); + hierarchiedMap.clear(); + cacheOfImmutableMaps.clear(); + } + + protected ChainedMap getRootMap() { + Object o = hierarchiedMap.get(null, null); + if (o == null) { + o = new ChainedMap(); + hierarchiedMap.put(null, null, o); + } + return (ChainedMap) o; + } + + /** + * @param service + * @return a map containing all the properties for the given service. + * @see #getProperties(String, String) + */ + public Map getProperties(String service) { + return getProperties(service, null); + } + + /** + * Return a map containing all the properties for the given port. The map is an immutable snapshot of the properties. + * Meaning that futur changes to the properties will NOT be reflected in the returned map. + * + * @param service + * @param port + * @return a map containing all the properties for the given port + */ + public Map getProperties(String service, String port) { + // no need to go further if no properties + if (hierarchiedMap.isEmpty()) return Collections.EMPTY_MAP; + + // else check the cache of ChainedMap already converted into immutable maps + Map cachedMap = (Map) this.cacheOfImmutableMaps.get(service, port); + if (cachedMap != null) { + return cachedMap; + } + + // else get the corresponding ChainedMap and convert it into a Map + ChainedMap cm = (ChainedMap) hierarchiedMap.get(service, port); + // if this port is not explicitly mentioned in the multimap, get the default values. + if (cm == null) { + cm = (ChainedMap) hierarchiedMap.get(service, null); + if (cm == null) { + // return the cached version of the root map + return getProperties(null, null); + } + } + Map snapshotMap = new HashMap(cm.size() * 15 / 10); + for (Object key : cm.keySet()) { + snapshotMap.put(key, cm.get(key)); + } + snapshotMap = Collections.unmodifiableMap(snapshotMap); + // put it in cache to avoid creating one map at each invocation + this.cacheOfImmutableMaps.put(service, port, snapshotMap); + return snapshotMap; + } + + public String getProperty(String property) { + return (String) getRootMap().get(property); + } + + public String getProperty(String service, String property) { + return getProperty(service, null, property); + } + + public String getProperty(String service, String port, String property) { + ChainedMap cm = (ChainedMap) hierarchiedMap.get(service, port); + // if this port is not explicitly mentioned in the multimap, get the default values. + if (cm == null) cm = getRootMap(); + return (String) cm.get(property); + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + private String[] parseProperty(String property) { + // service, port, targeted property + String[] res = new String[3]; + + int index = property.indexOf(prefix); + if (index <= 0) { + // assume there is no service/port prefixed, no need to go further + res[2] = property; + } else { + res[2] = property.substring(index + prefix.length()); // targeted property + String prefix = property.substring(0, index); + String[] t = prefix.split("\\."); + if (t.length > 2) { + throw new IllegalArgumentException("'.' cannot be mentioned more than twice in the before the property prefix"); + } + if (t.length >= 1) { + res[0] = t[0]; // service name + } + if (t.length > 1) { + res[1] = t[1]; // port name + } + } + return res; + } + + /** + * Link two Maps instances in a parent-child relation. Meaning that if a key is looked up but not found on the child, + * then the key will be looked up on the parent map. + * <br/>The raison d'etre of this class is to the [EMAIL PROTECTED] #keySet()} method. This methods returns a set of <strong>all</strong> the keys contained in the child and the parent. + * That's the main reason to not used the [EMAIL PROTECTED] java.util.Properties} class (which offers access to child keys only). + * <p/>The child has an immutable view of the parent map. Methods [EMAIL PROTECTED] #clear()} and [EMAIL PROTECTED] #remove(Object)} + * throw [EMAIL PROTECTED] UnsupportedOperationException}. Methods [EMAIL PROTECTED] #put(Object, Object)} and [EMAIL PROTECTED] #putAll(java.util.Map)} impacts only the child map. + * <br/>Methods [EMAIL PROTECTED] #clearLocally(Object)} + * <p/> + * This class does NOT implement the [EMAIL PROTECTED] java.util.Map} interface because methods [EMAIL PROTECTED] java.util.Map#entrySet()} }, + * [EMAIL PROTECTED] java.util.Map#values()} and [EMAIL PROTECTED] java.util.Map#keySet()} would NOT be backed by the Map itself. + * <br/> Contributions welcome to implement that part. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Alexis Midon</a> + */ + private static class ChainedMap { + + private ChainedMap parent; + private Map child; + + public ChainedMap() { + parent = null; + child = new HashMap(); + } + + public ChainedMap(ChainedMap parent) { + this.parent = parent; + this.child = new HashMap(); + } + + public ChainedMap getParent() { + return parent; + } + + public void setParent(ChainedMap parent) { + this.parent = parent; + } + + /** + * Perfom a look up on the child map only. + */ + public Object getLocally(Object key) { + return child.get(key); + } + + /** + * Clear the child map only, the parent map is not altered. + */ + public void clearLocally() { + child.clear(); + } + + /** + * Perform a look up for the given key on the child map, and if not found then perform the look up on the parent map. + * + * @param key + * @return + */ + public Object get(Object key) { + Object lv = getLocally(key); + if (lv != null) return lv; + else if (parent != null) return parent.get(key); + return null; + } + + /** + * Put this pair in the child map. + */ + public Object put(Object key, Object value) { + if (key == null) throw new NullPointerException("Null keys forbidden!"); + return child.put(key, value); + } + + + /** + * Put these pairs in the child map. + */ + public void putAll(Map t) { + for (Object e : t.entrySet()) { + put(((Map.Entry) e).getKey(), ((Map.Entry) e).getValue()); + } + } + + /** + * @throws UnsupportedOperationException + * @see #clearLocally() + */ + public void clear() { + throw new UnsupportedOperationException(); + } + + /** + * @throws UnsupportedOperationException + */ + public Object remove(Object key) { + throw new UnsupportedOperationException(); + } + + /** + * @return true if the child map is empty AND the parent map is null or empty as well. + * <pre>child.isEmpty() && (parent == null || parent.isEmpty());</pre> + */ + public boolean isEmpty() { + return child.isEmpty() && (parent == null || parent.isEmpty()); + } + + /** + * @return true if the child map contains this key OR the parent map is not null and contains this key. + * <pre>child.containsKey(key) || (parent != null && parent.containsKey(key));</pre> + */ + public boolean containsKey(Object key) { + if (key == null) throw new NullPointerException("Null keys forbidden!"); + return child.containsKey(key) || (parent != null && parent.containsKey(key)); + } + + /** + * @return true if the child map contains this value OR the parent is not null + * <pre>child.containsValue(value) || (parent != null && parent.containsValue(value));</pre> + */ + public boolean containsValue(Object value) { + return child.containsValue(value) || (parent != null && parent.containsValue(value)); + } + + public int size() { + return keySet().size(); + } + + /** + * @return a new set instance merging all keys contained in the child and parent maps. <strong>The returned set is not backed by the maps.</strong> + * Any references to the returned sets are hold at the holder's own risks. This breaks the general [EMAIL PROTECTED] java.util.Map#entrySet()} contract. + */ + public Set keySet() { + HashSet s = new HashSet(child.keySet()); + if (parent != null) s.addAll(parent.keySet()); + return s; + } + } +} Modified: ode/trunk/utils/src/main/java/org/apache/ode/utils/ObjectPrinter.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/main/java/org/apache/ode/utils/ObjectPrinter.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/utils/src/main/java/org/apache/ode/utils/ObjectPrinter.java (original) +++ ode/trunk/utils/src/main/java/org/apache/ode/utils/ObjectPrinter.java Thu Jun 5 14:14:08 2008 @@ -69,7 +69,7 @@ // NOTE: this causes blowups since array may be array of primitive type // which cannot be cast to 'Object[]' // else if (objects[i].getClass().isArray()){ -// buf.append(ArrayUtils.makeCollection(ArrayList.class, (Object[]) objects[i])); +// buf.append(CollectionUtils.makeCollection(ArrayList.class, (Object[]) objects[i])); else buf.append(objects[i]); Added: ode/trunk/utils/src/main/java/org/apache/ode/utils/WatchDog.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/main/java/org/apache/ode/utils/WatchDog.java?rev=663741&view=auto ============================================================================== --- ode/trunk/utils/src/main/java/org/apache/ode/utils/WatchDog.java (added) +++ ode/trunk/utils/src/main/java/org/apache/ode/utils/WatchDog.java Thu Jun 5 14:14:08 2008 @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ode.utils; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This class is based on [EMAIL PROTECTED] org.apache.log4j.helpers.FileWatchdog}.<p/> + * Modifications have been made to support additional abstract ressource and more events (creation, deletion and updates), and to allow "manual" + * invocations of [EMAIL PROTECTED] #check()} (i.e wihtout having to use a thread) while preserving time checking.<p/> + * Now two use cases coexist: + * <ol> + * <li>Pass an instance of [EMAIL PROTECTED] WatchDog} to a new thread ([EMAIL PROTECTED] WatchDog} is a [EMAIL PROTECTED] Runnable}). + * So that [EMAIL PROTECTED] WatchDog# check ()} will be called automatically every [EMAIL PROTECTED] delay} milliseconds.</li> + * <li>Invoke [EMAIL PROTECTED] WatchDog# check ()} only when you feel like it. If the expiration date previously set is lower than NOW then event + * callback methods will be invoked accordingly.</li> + * </ol> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Alexis Midon</a> + */ +public class WatchDog<T> implements Runnable { + static final public long DEFAULT_DELAY = 30000; + final Log log = LogFactory.getLog(getClass()); + + private long expire; + private T lastModif; + private long delay; + private boolean existedBefore, warnedAlready, interrupted; + protected final Mutable<T> mutable; + + /** + * @param mutable the object to watch closely + * @param delay between two checks + */ + public WatchDog(Mutable<T> mutable, long delay) { + this(mutable); + this.delay = delay; + } + + /** + * @see #WatchDog(org.apache.ode.utils.WatchDog.Mutable, long) + */ + public WatchDog(Mutable<T> mutable) { + this.mutable = mutable; + this.delay = DEFAULT_DELAY; + } + + protected boolean isInitialized() { + return true; + } + + /** + * Called by [EMAIL PROTECTED] #check()} if the object is not [EMAIL PROTECTED] #isInitialized initialized} and the [EMAIL PROTECTED] WatchDog.Mutable#exists()} resource does not exist}. + * <br/> This method might called to reset the object. + * + * @throws Exception + */ + protected void init() { + } + + /** + * Called only if the resource previously existed and now does not exist. + * <br/>The default implementation invokes [EMAIL PROTECTED] #init()} . + * + * @throws Exception + */ + protected void doOnDelete() { + init(); + } + + /** + * Called only if the resource previously existed but the [EMAIL PROTECTED] WatchDog.Mutable#lastModified()} timestamp has changed (greater than the previous value). + * <br/>The default implementation invokes [EMAIL PROTECTED] #init()} . + * + * @throws Exception + */ + protected void doOnUpdate() { + init(); + } + + public long getDelay() { + return delay; + } + + public void setDelay(long delay) { + this.delay = delay; + } + + public void run() { + try { + while (!interrupted) { + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + // no interruption expected + } + check(); + } + } catch (Exception e) { + log.warn("Exception occured. Thread will stop", e); + } + } + + public final void check() { + long now = System.currentTimeMillis(); + if (expire <= now) { + expire = now + delay; + + if (mutable.exists()) { + existedBefore = true; + if (lastModif==null || mutable.hasChangedSince(lastModif)) { + lastModif = mutable.lastModified(); + if (log.isDebugEnabled()) + log.debug(mutable + " has been modified"); + doOnUpdate(); + warnedAlready = false; + } + } else if (!isInitialized()) { + // no resource and first time + init(); + } else { + if (existedBefore) { + existedBefore = false; + lastModif = null; + doOnDelete(); + } + if (!warnedAlready) { + warnedAlready = true; + if (log.isDebugEnabled()) log.debug(mutable + "] does not exist."); + } + } + } + } + + /** + * have you said that duck typing would be nice? + */ + public interface Mutable<T> { + boolean exists(); + + boolean hasChangedSince(T since); + + T lastModified(); + } + +} Modified: ode/trunk/utils/src/main/java/org/apache/ode/utils/fs/FileWatchDog.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/main/java/org/apache/ode/utils/fs/FileWatchDog.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/utils/src/main/java/org/apache/ode/utils/fs/FileWatchDog.java (original) +++ ode/trunk/utils/src/main/java/org/apache/ode/utils/fs/FileWatchDog.java Thu Jun 5 14:14:08 2008 @@ -19,121 +19,40 @@ package org.apache.ode.utils.fs; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.apache.ode.utils.WatchDog; import java.io.File; -/** - * This class is based on [EMAIL PROTECTED] org.apache.log4j.helpers.FileWatchdog}.<p/> - * Modifications have been made to support additional file events (creation, deletion and updates), and to allow "manual" - * invocations of [EMAIL PROTECTED] #checkAndConfigure()} (i.e wihtout having to use a thread) while preserving time checking.<p/> - * Now two use cases coexist: - * <ol> - * <li>Pass an instance of [EMAIL PROTECTED] FileWatchDog} to a new thread ([EMAIL PROTECTED] FileWatchDog} is a [EMAIL PROTECTED] Runnable}). - * So that [EMAIL PROTECTED] FileWatchDog#checkAndConfigure()} will be called automatically every [EMAIL PROTECTED] delay} milliseconds.</li> - * <li>Invoke [EMAIL PROTECTED] FileWatchDog#checkAndConfigure()} only when you feel like it. If the expiration date previously set is lower than NOW then event - * callback methods will be invoked accordingly.</li> - * </ol> - * - * @author Ceki Gülcü - * @author <a href="mailto:[EMAIL PROTECTED]">Alexis Midon</a> - */ -public class FileWatchDog implements Runnable { - static final public long DEFAULT_DELAY = 60000; - private final Log log; - - long expire; - long lastModif; - long delay = DEFAULT_DELAY; - boolean fileExistedBefore, warnedAlready, interrupted; - protected final File file; +public class FileWatchDog extends WatchDog<Long> { - protected FileWatchDog(File file, long delay) { - this(file); - this.delay = delay; - } + protected final File file; - protected FileWatchDog(File file) { + public FileWatchDog(File file, long delay) { + super(new FileDecorator(file),delay); this.file = file; - log = LogFactory.getLog(FileWatchDog.class); - } - - protected boolean isInitialized() throws Exception { - return true; - } - - protected void init() throws Exception { } - protected void doOnDelete() throws Exception { - init(); + public FileWatchDog(File file) { + this(file, WatchDog.DEFAULT_DELAY); } - protected void doOnUpdate() throws Exception { - init(); - } - - public long getDelay() { - return delay; - } + static class FileDecorator implements WatchDog.Mutable<Long>{ + File file; - public void setDelay(long delay) { - this.delay = delay; - } + FileDecorator(File file) { + this.file = file; + } - public void run() { - try { - while (!interrupted) { - try { - Thread.currentThread().sleep(delay); - } catch (InterruptedException e) { - // no interruption expected - } - checkAndConfigure(); - } - } catch (Exception e) { - log.warn("Exception occured. Thread will stop", e); + public boolean exists() { + return file.exists(); } - } + public boolean hasChangedSince(Long since) { + return lastModified().longValue()>since.longValue(); + } - public final void checkAndConfigure() throws Exception { - long now = System.currentTimeMillis(); - if (expire <= now) { - expire = now + delay; - boolean fileExists; - try { - fileExists = file.exists(); - } catch (SecurityException e) { - log.warn("Was not allowed to read check file existance, file:[" + file.getPath() + "]."); - interrupted = true; // there is no point in continuing - return; - } - - if (fileExists) { - fileExistedBefore = true; - long l = file.lastModified(); - if (l > lastModif) { - lastModif = l; - if (log.isDebugEnabled()) - log.debug("File [" + file + "] has been modified"); - doOnUpdate(); - warnedAlready = false; - } - } else if (!isInitialized()) { - // first time and no file - init(); - } else { - if (fileExistedBefore) { - fileExistedBefore = false; - doOnDelete(); - } - if (!warnedAlready) { - warnedAlready = true; - if (log.isDebugEnabled()) log.debug("[" + file + "] does not exist."); - } - } + public Long lastModified() { + return Long.valueOf(file.lastModified()); } } Added: ode/trunk/utils/src/test/java/org/apache/ode/utils/HierarchiedPropertiesTest.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/test/java/org/apache/ode/utils/HierarchiedPropertiesTest.java?rev=663741&view=auto ============================================================================== --- ode/trunk/utils/src/test/java/org/apache/ode/utils/HierarchiedPropertiesTest.java (added) +++ ode/trunk/utils/src/test/java/org/apache/ode/utils/HierarchiedPropertiesTest.java Thu Jun 5 14:14:08 2008 @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ode.utils; + +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.List; +import java.util.Arrays; + +/** + * @author <a href="mailto:[EMAIL PROTECTED]">Alexis Midon</a> + */ +public class HierarchiedPropertiesTest extends TestCase { + protected HierarchiedProperties hp; + + protected void setUp() throws Exception { + File file = new File(getClass().getResource("/hierarchied.properties").toURI()); + hp = new HierarchiedProperties(file); + } + + public void testGetProperty() { + String msg = "Returned value does not match expected value for this property!"; + assertEquals(msg, hp.getProperty("max-redirects"), "30"); + assertEquals(msg, hp.getProperty("brel-service", "max-redirects"), "40"); + assertEquals(msg, hp.getProperty("brel-service", "port-of-amsterdam", "max-redirects"), "60"); + assertEquals(msg, hp.getProperty("film-service", "timeout"), "40000"); + assertEquals(msg, hp.getProperty("film-service", "port-of-cannes", "timeout"), "50000"); + assertEquals(msg, hp.getProperty("brel-service", "port-of-amsterdam", "timeout"), "40000"); + assertEquals(msg, hp.getProperty("ode.a.property.beginning.with.the.prefix.but.no.service"), "so green or red?"); + } + + public void testGetProperties(){ + final List keys = Arrays.asList("timeout", "max-redirects", "ode.a.property.beginning.with.the.prefix.but.no.service"); + Map map = hp.getProperties("film-service"); + assertEquals("Number of properties is wrong",keys.size(), map.size()); + assertEquals("40000", map.get("timeout")); + assertEquals("30", map.get("max-redirects")); + assertEquals("so green or red?", map.get("ode.a.property.beginning.with.the.prefix.but.no.service")); + } + + + public void testCachedGetProperties(){ + assertSame("Snapshot maps should be cached!", hp.getProperties("film-service"), hp.getProperties("film-service")); + assertSame("Snapshot maps should be cached!", hp.getProperties("film-service", "port-of-cannes"), hp.getProperties("film-service", "port-of-cannes")); + assertSame("Snapshot maps should be cached!", hp.getProperties("unknown-service"), hp.getProperties("unknown-service")); + } + + public void testWithNoFile() throws IOException { + File file = new File("/a-file-that-does-not-exist"); + Map m = new HierarchiedProperties(file).getProperties("a-service", "a-port"); + assertEquals("Should be empty", 0, m.size()); + } + +} Modified: ode/trunk/utils/src/test/java/org/apache/ode/utils/wsdl/WsdlUtilsTest.java URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/test/java/org/apache/ode/utils/wsdl/WsdlUtilsTest.java?rev=663741&r1=663740&r2=663741&view=diff ============================================================================== --- ode/trunk/utils/src/test/java/org/apache/ode/utils/wsdl/WsdlUtilsTest.java (original) +++ ode/trunk/utils/src/test/java/org/apache/ode/utils/wsdl/WsdlUtilsTest.java Thu Jun 5 14:14:08 2008 @@ -42,7 +42,7 @@ public class WsdlUtilsTest extends TestCase { private Definition definition; private Service dummyService; - + protected void setUp() throws Exception { super.setUp(); @@ -178,8 +178,8 @@ Map.Entry e = (Map.Entry) it.next(); Port port = (Port) e.getValue(); - if("DummyService_port_with_empty_binding".equals(port.getName()) - || "DummyService_port_with_no_binding".equals(port.getName())){ + if ("DummyService_port_with_empty_binding".equals(port.getName()) + || "DummyService_port_with_no_binding".equals(port.getName())) { continue; } Added: ode/trunk/utils/src/test/resources/hierarchied.properties URL: http://svn.apache.org/viewvc/ode/trunk/utils/src/test/resources/hierarchied.properties?rev=663741&view=auto ============================================================================== --- ode/trunk/utils/src/test/resources/hierarchied.properties (added) +++ ode/trunk/utils/src/test/resources/hierarchied.properties Thu Jun 5 14:14:08 2008 @@ -0,0 +1,10 @@ + + +timeout=40000 +max-redirects=30 + +film-service.port-of-cannes.ode.timeout=50000 +brel-service.ode.max-redirects=40 +brel-service.port-of-amsterdam.ode.max-redirects=60 +ode.a.property.beginning.with.the.prefix.but.no.service=so green or red? +
