http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/ObjectInputStreamWithClassLoader.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/ObjectInputStreamWithClassLoader.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/ObjectInputStreamWithClassLoader.java new file mode 100644 index 0000000..077225d --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/ObjectInputStreamWithClassLoader.java @@ -0,0 +1,195 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * @author <a href="mailto:[email protected]">Clebert Suconic</a> + */ +public class ObjectInputStreamWithClassLoader extends ObjectInputStream +{ + + // Constants ------------------------------------------------------------------------------------ + + // Attributes ----------------------------------------------------------------------------------- + + // Static --------------------------------------------------------------------------------------- + + // Constructors --------------------------------------------------------------------------------- + + public ObjectInputStreamWithClassLoader(final InputStream in) throws IOException + { + super(in); + } + + // Public --------------------------------------------------------------------------------------- + + // Package protected ---------------------------------------------------------------------------- + + // Protected ------------------------------------------------------------------------------------ + + @Override + protected Class resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException + { + if (System.getSecurityManager() == null) + { + return resolveClass0(desc); + } + else + { + try + { + return AccessController.doPrivileged(new PrivilegedExceptionAction<Class>() + { + @Override + public Class run() throws Exception + { + return resolveClass0(desc); + } + }); + } + catch (PrivilegedActionException e) + { + throw unwrapException(e); + } + } + } + + @Override + protected Class resolveProxyClass(final String[] interfaces) throws IOException, ClassNotFoundException + { + if (System.getSecurityManager() == null) + { + return resolveProxyClass0(interfaces); + } + else + { + try + { + return AccessController.doPrivileged(new PrivilegedExceptionAction<Class>() + { + @Override + public Class run() throws Exception + { + return resolveProxyClass0(interfaces); + } + }); + } + catch (PrivilegedActionException e) + { + throw unwrapException(e); + } + } + } + + // Private -------------------------------------------------------------------------------------- + + private Class resolveClass0(final ObjectStreamClass desc) throws IOException, ClassNotFoundException + { + String name = desc.getName(); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try + { + // HORNETQ-747 https://issues.jboss.org/browse/HORNETQ-747 + // Use Class.forName instead of ClassLoader.loadClass to avoid issues with loading arrays + Class clazz = Class.forName(name, false, loader); + // sanity check only.. if a classLoader can't find a clazz, it will throw an exception + if (clazz == null) + { + return super.resolveClass(desc); + } + else + { + return clazz; + } + } + catch (ClassNotFoundException e) + { + return super.resolveClass(desc); + } + } + + private Class resolveProxyClass0(String[] interfaces) throws IOException, ClassNotFoundException + { + ClassLoader latestLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader nonPublicLoader = null; + boolean hasNonPublicInterface = false; + // define proxy in class loader of non-public interface(s), if any + Class[] classObjs = new Class[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) + { + Class cl = Class.forName(interfaces[i], false, latestLoader); + if ((cl.getModifiers() & Modifier.PUBLIC) == 0) + { + if (hasNonPublicInterface) + { + if (nonPublicLoader != cl.getClassLoader()) + { + throw new IllegalAccessError("conflicting non-public interface class loaders"); + } + } + else + { + nonPublicLoader = cl.getClassLoader(); + hasNonPublicInterface = true; + } + } + classObjs[i] = cl; + } + try + { + return Proxy.getProxyClass(hasNonPublicInterface ? nonPublicLoader : latestLoader, classObjs); + } + catch (IllegalArgumentException e) + { + throw new ClassNotFoundException(null, e); + } + } + + private RuntimeException unwrapException(PrivilegedActionException e) throws IOException, ClassNotFoundException + { + Throwable c = e.getCause(); + if (c instanceof IOException) + { + throw (IOException)c; + } + else if (c instanceof ClassNotFoundException) + { + throw (ClassNotFoundException)c; + } + else if (c instanceof RuntimeException) + { + throw (RuntimeException)c; + } + else if (c instanceof Error) + { + throw (Error)c; + } + else + { + throw new RuntimeException(c); + } + } + + // Inner classes -------------------------------------------------------------------------------- + +}
http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/OrderedExecutorFactory.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/OrderedExecutorFactory.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/OrderedExecutorFactory.java new file mode 100644 index 0000000..7c8ee02 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/OrderedExecutorFactory.java @@ -0,0 +1,143 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; + +import org.apache.activemq6.api.core.HornetQInterruptedException; +import org.apache.activemq6.core.client.HornetQClientLogger; + + +/** + * A factory for producing executors that run all tasks in order, which delegate to a single common executor instance. + * + * @author <a href="[email protected]">David Lloyd</a> + * @author <a href="mailto:[email protected]">Tim Fox</a> + */ +public final class OrderedExecutorFactory implements ExecutorFactory +{ + private final Executor parent; + + /** + * Construct a new instance delegating to the given parent executor. + * + * @param parent the parent executor + */ + public OrderedExecutorFactory(final Executor parent) + { + this.parent = parent; + } + + /** + * Get an executor that always executes tasks in order. + * + * @return an ordered executor + */ + public Executor getExecutor() + { + return new OrderedExecutor(parent); + } + + /** + * An executor that always runs all tasks in order, using a delegate executor to run the tasks. + * <p/> + * More specifically, any call B to the {@link #execute(Runnable)} method that happens-after another call A to the + * same method, will result in B's task running after A's. + */ + private static final class OrderedExecutor implements Executor + { + private final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<Runnable>(); + + // @protected by tasks + private boolean running; + + private final Executor parent; + + private final Runnable runner; + + /** + * Construct a new instance. + * + * @param parent the parent executor + */ + public OrderedExecutor(final Executor parent) + { + this.parent = parent; + runner = new Runnable() + { + public void run() + { + for (;;) + { + // Optimization, first try without any locks + Runnable task = tasks.poll(); + if (task == null) + { + synchronized (tasks) + { + // if it's null we need to retry now holding the lock on tasks + // this is because running=false and tasks.empty must be an atomic operation + // so we have to retry before setting the tasks to false + // this is a different approach to the anti-pattern on synchronize-retry, + // as this is just guaranteeing the running=false and tasks.empty being an atomic operation + task = tasks.poll(); + if (task == null) + { + running = false; + return; + } + } + } + try + { + task.run(); + } + catch (HornetQInterruptedException e) + { + // This could happen during shutdowns. Nothing to be concerned about here + HornetQClientLogger.LOGGER.debug("Interrupted Thread", e); + } + catch (Throwable t) + { + HornetQClientLogger.LOGGER.caughtunexpectedThrowable(t); + } + } + } + }; + } + + /** + * Run a task. + * + * @param command the task to run. + */ + public void execute(final Runnable command) + { + synchronized (tasks) + { + tasks.add(command); + if (!running) + { + running = true; + parent.execute(runner); + } + } + } + + public String toString() + { + return "OrderedExecutor(running=" + running + ", tasks=" + tasks + ")"; + } + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedList.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedList.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedList.java new file mode 100644 index 0000000..668f95b --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedList.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + + +/** + * A type of linked list which maintains items according to a priority + * and allows adding and removing of elements at both ends, and peeking + * + * @author <a href="mailto:[email protected]">Tim Fox</a> + * @version <tt>$Revision: 1174 $</tt> + */ +public interface PriorityLinkedList<T> +{ + void addHead(T t, int priority); + + void addTail(T t, int priority); + + T poll(); + + void clear(); + + int size(); + + LinkedListIterator<T> iterator(); + + boolean isEmpty(); +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedListImpl.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedListImpl.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedListImpl.java new file mode 100644 index 0000000..50e7f97 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/PriorityLinkedListImpl.java @@ -0,0 +1,277 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.lang.reflect.Array; +import java.util.NoSuchElementException; + +/** + * A priority linked list implementation + * <p> + * It implements this by maintaining an individual LinkedBlockingDeque for each priority level. + * + * @author <a href="mailto:[email protected]">Tim Fox</a> + * @author <a href="mailto:[email protected]">Jeff Mesnil</a> + * @version <tt>$Revision: 1174 $</tt> + */ +public class PriorityLinkedListImpl<T> implements PriorityLinkedList<T> +{ + protected LinkedListImpl<T>[] levels; + + private int size; + + private int lastReset; + + private int highestPriority = -1; + + private int lastPriority = -1; + + public PriorityLinkedListImpl(final int priorities) + { + levels = (LinkedListImpl<T>[]) Array.newInstance(LinkedListImpl.class, priorities); + + for (int i = 0; i < priorities; i++) + { + levels[i] = new LinkedListImpl<T>(); + } + } + + private void checkHighest(final int priority) + { + if (lastPriority != priority || priority > highestPriority) + { + lastPriority = priority; + if (lastReset == Integer.MAX_VALUE) + { + lastReset = 0; + } + else + { + lastReset++; + } + } + + if (priority > highestPriority) + { + highestPriority = priority; + } + } + + public void addHead(final T t, final int priority) + { + checkHighest(priority); + + levels[priority].addHead(t); + + size++; + } + + public void addTail(final T t, final int priority) + { + checkHighest(priority); + + levels[priority].addTail(t); + + size++; + } + + public T poll() + { + T t = null; + + // We are just using a simple prioritization algorithm: + // Highest priority refs always get returned first. + // This could cause starvation of lower priority refs. + + // TODO - A better prioritization algorithm + + for (int i = highestPriority; i >= 0; i--) + { + LinkedListImpl<T> ll = levels[i]; + + if (ll.size() != 0) + { + t = ll.poll(); + + if (t != null) + { + size--; + + if (ll.size() == 0) + { + if (highestPriority == i) + { + highestPriority--; + } + } + } + + break; + } + } + + return t; + } + + public void clear() + { + for (LinkedListImpl<T> list : levels) + { + list.clear(); + } + + size = 0; + } + + public int size() + { + return size; + } + + public boolean isEmpty() + { + return size == 0; + } + + public LinkedListIterator<T> iterator() + { + return new PriorityLinkedListIterator(); + } + + private class PriorityLinkedListIterator implements LinkedListIterator<T> + { + private int index; + + private final LinkedListIterator<T>[] cachedIters = new LinkedListIterator[levels.length]; + + private LinkedListIterator<T> lastIter; + + private int resetCount = lastReset; + + volatile boolean closed = false; + + PriorityLinkedListIterator() + { + index = levels.length - 1; + } + + @Override + protected void finalize() + { + close(); + } + + public void repeat() + { + if (lastIter == null) + { + throw new NoSuchElementException(); + } + + lastIter.repeat(); + } + + public void close() + { + if (!closed) + { + closed = true; + lastIter = null; + + for (LinkedListIterator<T> iter : cachedIters) + { + if (iter != null) + { + iter.close(); + } + } + } + } + + private void checkReset() + { + if (lastReset != resetCount) + { + index = highestPriority; + + resetCount = lastReset; + } + } + + public boolean hasNext() + { + checkReset(); + + while (index >= 0) + { + lastIter = cachedIters[index]; + + if (lastIter == null) + { + lastIter = cachedIters[index] = levels[index].iterator(); + } + + boolean b = lastIter.hasNext(); + + if (b) + { + return true; + } + + index--; + + if (index < 0) + { + index = levels.length - 1; + + break; + } + } + return false; + } + + public T next() + { + if (lastIter == null) + { + throw new NoSuchElementException(); + } + + return lastIter.next(); + } + + public void remove() + { + if (lastIter == null) + { + throw new NoSuchElementException(); + } + + lastIter.remove(); + + // This next statement would be the equivalent of: + // if (index == highestPriority && levels[index].size() == 0) + // However we have to keep checking all the previous levels + // otherwise we would cache a max that will not exist + // what would make us eventually having hasNext() returning false + // as a bug + // Part of the fix for HORNETQ-705 + for (int i = index; i >= 0 && levels[index].size() == 0; i--) + { + highestPriority = i; + } + + size--; + } + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/Random.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/Random.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/Random.java new file mode 100644 index 0000000..45a0131 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/Random.java @@ -0,0 +1,46 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.io.Serializable; + +/** + * A Random + * + * @author <a href="mailto:[email protected]">Tim Fox</a> + * + * Created 28 Nov 2008 10:28:28 + * + * + */ +public class Random implements Serializable +{ + private static int extraSeed; + + private static final long serialVersionUID = 40335522290950498L; + + private static synchronized long getSeed() + { + long seed = System.currentTimeMillis() + Random.extraSeed++; + + return seed; + } + + private final java.util.Random random = new java.util.Random(Random.getSeed()); + + public java.util.Random getRandom() + { + return random; + } + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SecurityFormatter.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SecurityFormatter.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SecurityFormatter.java new file mode 100644 index 0000000..89de2fb --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SecurityFormatter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import org.apache.activemq6.core.security.Role; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class SecurityFormatter +{ + public static Set<Role> createSecurity(String sendRoles, String consumeRoles, String createDurableQueueRoles, String deleteDurableQueueRoles, String createNonDurableQueueRoles, String deleteNonDurableQueueRoles, String manageRoles) + { + List<String> createDurableQueue = toList(createDurableQueueRoles); + List<String> deleteDurableQueue = toList(deleteDurableQueueRoles); + List<String> createNonDurableQueue = toList(createNonDurableQueueRoles); + List<String> deleteNonDurableQueue = toList(deleteNonDurableQueueRoles); + List<String> send = toList(sendRoles); + List<String> consume = toList(consumeRoles); + List<String> manage = toList(manageRoles); + + Set<String> allRoles = new HashSet<String>(); + allRoles.addAll(createDurableQueue); + allRoles.addAll(deleteDurableQueue); + allRoles.addAll(createNonDurableQueue); + allRoles.addAll(deleteNonDurableQueue); + allRoles.addAll(send); + allRoles.addAll(consume); + allRoles.addAll(manage); + + Set<Role> roles = new HashSet<Role>(allRoles.size()); + for (String role : allRoles) + { + roles.add(new Role(role, + send.contains(role), + consume.contains(role), + createDurableQueue.contains(role), + deleteDurableQueue.contains(role), + createNonDurableQueue.contains(role), + deleteNonDurableQueue.contains(role), + manageRoles.contains(role))); + } + return roles; + } + + + private static List<String> toList(final String commaSeparatedString) + { + List<String> list = new ArrayList<String>(); + if (commaSeparatedString == null || commaSeparatedString.trim().length() == 0) + { + return list; + } + String[] values = commaSeparatedString.split(","); + for (int i = 0; i < values.length; i++) + { + list.add(values[i].trim()); + } + return list; + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SimpleIDGenerator.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SimpleIDGenerator.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SimpleIDGenerator.java new file mode 100644 index 0000000..3ab77b9 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SimpleIDGenerator.java @@ -0,0 +1,54 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +/** + * A SimpleIDGenerator + * + * @author <a href="mailto:[email protected]">Tim Fox</a> + * + */ +public class SimpleIDGenerator implements IDGenerator +{ + private long idSequence; + + private boolean wrapped; + + public SimpleIDGenerator(final long startID) + { + idSequence = startID; + } + + public synchronized long generateID() + { + long id = idSequence++; + + if (idSequence == Long.MIN_VALUE) + { + wrapped = true; + } + + if (wrapped) + { + // Wrap - Very unlikely to happen + throw new IllegalStateException("Exhausted ids to use!"); + } + + return id; + } + + public synchronized long getCurrentID() + { + return idSequence; + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SizeFormatterUtil.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SizeFormatterUtil.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SizeFormatterUtil.java new file mode 100644 index 0000000..2214469 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SizeFormatterUtil.java @@ -0,0 +1,70 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +/** + * A SizeFormatterUtil + * + * @author <a href="mailto:[email protected]">Jeff Mesnil</a> + * + * + */ +public class SizeFormatterUtil +{ + + // Constants ----------------------------------------------------- + + private static long oneKiB = 1024; + + private static long oneMiB = SizeFormatterUtil.oneKiB * 1024; + + private static long oneGiB = SizeFormatterUtil.oneMiB * 1024; + + // Attributes ---------------------------------------------------- + + // Static -------------------------------------------------------- + + public static String sizeof(final long size) + { + double s = Long.valueOf(size).doubleValue(); + String suffix = "B"; + if (s > SizeFormatterUtil.oneGiB) + { + s /= SizeFormatterUtil.oneGiB; + suffix = "GiB"; + } + else if (s > SizeFormatterUtil.oneMiB) + { + s /= SizeFormatterUtil.oneMiB; + suffix = "MiB"; + } + else if (s > SizeFormatterUtil.oneKiB) + { + s /= SizeFormatterUtil.oneKiB; + suffix = "kiB"; + } + return String.format("%.2f %s", s, suffix); + } + // Constructors -------------------------------------------------- + + // Public -------------------------------------------------------- + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + // Inner classes ------------------------------------------------- + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SoftValueHashMap.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SoftValueHashMap.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SoftValueHashMap.java new file mode 100644 index 0000000..dbff41b --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/SoftValueHashMap.java @@ -0,0 +1,434 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.activemq6.core.client.HornetQClientLogger; + +/** + * A SoftValueHashMap + * + * @author <a href="mailto:[email protected]">Clebert Suconic</a> + * + * + */ +public class SoftValueHashMap<K, V extends SoftValueHashMap.ValueCache> implements Map<K, V> +{ + private final boolean isTrace = HornetQClientLogger.LOGGER.isTraceEnabled(); + + // The soft references that are already good. + // too bad there's no way to override the queue method on ReferenceQueue, so I wouldn't need this + private final ReferenceQueue<V> refQueue = new ReferenceQueue<V>(); + + private final Map<K, AggregatedSoftReference> mapDelegate = new HashMap<K, AggregatedSoftReference>(); + + private final AtomicLong usedCounter = new AtomicLong(0); + + private int maxElements; + + // Constants ----------------------------------------------------- + + // Attributes ---------------------------------------------------- + + // Static -------------------------------------------------------- + + public abstract interface ValueCache + { + boolean isLive(); + } + + // Constructors -------------------------------------------------- + + public SoftValueHashMap(final int maxElements) + { + this.maxElements = maxElements; + } + + // Public -------------------------------------------------------- + + public void setMaxElements(final int maxElements) + { + this.maxElements = maxElements; + checkCacheSize(); + } + + public int getMaxEelements() + { + return this.maxElements; + } + + /** + * @see java.util.Map#size() + */ + public int size() + { + processQueue(); + return mapDelegate.size(); + } + + /** + * @see java.util.Map#isEmpty() + */ + public boolean isEmpty() + { + processQueue(); + return mapDelegate.isEmpty(); + } + + /** + * @param key + * @see java.util.Map#containsKey(java.lang.Object) + */ + public boolean containsKey(final Object key) + { + processQueue(); + return mapDelegate.containsKey(key); + } + + /** + * @param value + * @see java.util.Map#containsValue(java.lang.Object) + */ + public boolean containsValue(final Object value) + { + processQueue(); + for (AggregatedSoftReference valueIter : mapDelegate.values()) + { + V valueElement = valueIter.get(); + if (valueElement != null && value.equals(valueElement)) + { + return true; + } + + } + return false; + } + + /** + * @param key + * @see java.util.Map#get(java.lang.Object) + */ + public V get(final Object key) + { + processQueue(); + AggregatedSoftReference value = mapDelegate.get(key); + if (value != null) + { + value.used(); + return value.get(); + } + else + { + return null; + } + } + + /** + * @param key + * @param value + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + public V put(final K key, final V value) + { + processQueue(); + AggregatedSoftReference newRef = createReference(key, value); + AggregatedSoftReference oldRef = mapDelegate.put(key, newRef); + checkCacheSize(); + newRef.used(); + if (oldRef != null) + { + return oldRef.get(); + } + else + { + return null; + } + } + + private void checkCacheSize() + { + if (maxElements > 0 && mapDelegate.size() > maxElements) + { + TreeSet<AggregatedSoftReference> usedReferences = new TreeSet<AggregatedSoftReference>(new ComparatorAgregated()); + + for (AggregatedSoftReference ref : mapDelegate.values()) + { + V v = ref.get(); + + if (v != null && !v.isLive()) + { + usedReferences.add(ref); + } + } + + for (AggregatedSoftReference ref : usedReferences) + { + if (ref.used > 0) + { + Object removed = mapDelegate.remove(ref.key); + + if (isTrace) + { + HornetQClientLogger.LOGGER.trace("Removing " + removed + " with id = " + ref.key + " from SoftValueHashMap"); + } + + if (mapDelegate.size() <= maxElements) + { + break; + } + } + } + } + } + + class ComparatorAgregated implements Comparator<AggregatedSoftReference> + { + public int compare(AggregatedSoftReference o1, AggregatedSoftReference o2) + { + long k = o1.used - o2.used; + + if (k > 0) + { + return 1; + } + else if (k < 0) + { + return -1; + } + + k = o1.hashCode() - o2.hashCode(); + + if (k > 0) + { + return 1; + } + else if (k < 0) + { + return -1; + } + else + { + return 0; + } + } + } + + /** + * @param key + * @see java.util.Map#remove(java.lang.Object) + */ + public V remove(final Object key) + { + processQueue(); + AggregatedSoftReference ref = mapDelegate.remove(key); + if (ref != null) + { + return ref.get(); + } + else + { + return null; + } + } + + /** + * @param m + * @see java.util.Map#putAll(java.util.Map) + */ + public void putAll(final Map<? extends K, ? extends V> m) + { + processQueue(); + for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) + { + put(e.getKey(), e.getValue()); + } + } + + /** + * @see java.util.Map#clear() + */ + public void clear() + { + mapDelegate.clear(); + } + + /** + * @see java.util.Map#keySet() + */ + public Set<K> keySet() + { + processQueue(); + return mapDelegate.keySet(); + } + + /** + * @see java.util.Map#values() + */ + public Collection<V> values() + { + processQueue(); + ArrayList<V> list = new ArrayList<V>(); + + for (AggregatedSoftReference refs : mapDelegate.values()) + { + V value = refs.get(); + if (value != null) + { + list.add(value); + } + } + + return list; + } + + /** + * @see java.util.Map#entrySet() + */ + public Set<java.util.Map.Entry<K, V>> entrySet() + { + processQueue(); + HashSet<Map.Entry<K, V>> set = new HashSet<Map.Entry<K, V>>(); + for (Map.Entry<K, AggregatedSoftReference> pair : mapDelegate.entrySet()) + { + V value = pair.getValue().get(); + if (value != null) + { + set.add(new EntryElement<K, V>(pair.getKey(), value)); + } + } + return set; + } + + /** + * @param o + * @see java.util.Map#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object o) + { + processQueue(); + return mapDelegate.equals(o); + } + + /** + * @see java.util.Map#hashCode() + */ + @Override + public int hashCode() + { + return mapDelegate.hashCode(); + } + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + @SuppressWarnings("unchecked") + private void processQueue() + { + AggregatedSoftReference ref = null; + while ((ref = (AggregatedSoftReference)this.refQueue.poll()) != null) + { + mapDelegate.remove(ref.key); + } + } + + private AggregatedSoftReference createReference(final K key, final V value) + { + AggregatedSoftReference ref = new AggregatedSoftReference(key, value); + return ref; + } + + // Inner classes ------------------------------------------------- + + class AggregatedSoftReference extends SoftReference<V> + { + final K key; + + long used = 0; + + public long getUsed() + { + return used; + } + + public void used() + { + used = usedCounter.incrementAndGet(); + } + + public AggregatedSoftReference(final K key, final V referent) + { + super(referent, refQueue); + this.key = key; + } + + @Override + public String toString() + { + return "AggregatedSoftReference [key=" + key + ", used=" + used + "]"; + } + } + + static final class EntryElement<K, V> implements Map.Entry<K, V> + { + final K key; + + volatile V value; + + EntryElement(final K key, final V value) + { + this.key = key; + this.value = value; + } + + /* (non-Javadoc) + * @see java.util.Map.Entry#getKey() + */ + public K getKey() + { + return key; + } + + /* (non-Javadoc) + * @see java.util.Map.Entry#getValue() + */ + public V getValue() + { + return value; + } + + /* (non-Javadoc) + * @see java.util.Map.Entry#setValue(java.lang.Object) + */ + public V setValue(final V value) + { + this.value = value; + return value; + } + } + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TimeAndCounterIDGenerator.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TimeAndCounterIDGenerator.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TimeAndCounterIDGenerator.java new file mode 100644 index 0000000..7aa6cb6 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TimeAndCounterIDGenerator.java @@ -0,0 +1,167 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * A TimeAndCounterIDGenerator + * <p> + * This IDGenerator doesn't support more than 16777215 IDs per 16 millisecond. It would throw an exception if this happens. + * </p> + * + * @author <a href="mailto:[email protected]">Clebert Suconic</a> + * @author <a href="mailto:[email protected]">Tim Fox</a> Created Sep 24, 2008 11:54:10 AM + */ +public class TimeAndCounterIDGenerator implements IDGenerator +{ + // Constants ---------------------------------------------------- + + /** + * Bits to move the date accordingly to MASK_TIME + */ + private static final int BITS_TO_MOVE = 20; + + public static final long MASK_TIME = 0x7fffffffff0L; + + // 44 bits of time and 20 bits of counter + + public static final long ID_MASK = 0xffffffL; + + private static final long TIME_ID_MASK = 0x7fffffffff000000L; + + // Attributes ---------------------------------------------------- + + private final AtomicLong counter = new AtomicLong(0); + + private volatile boolean wrapped = false; + + private volatile long tmMark; + + // Static -------------------------------------------------------- + + // Constructors -------------------------------------------------- + + public TimeAndCounterIDGenerator() + { + refresh(); + } + + // Public -------------------------------------------------------- + + // Public -------------------------------------------------------- + + public long generateID() + { + long idReturn = counter.incrementAndGet(); + + if ((idReturn & TimeAndCounterIDGenerator.ID_MASK) == 0) + { + final long timePortion = idReturn & TimeAndCounterIDGenerator.TIME_ID_MASK; + + // Wrapping ID logic + + if (timePortion >= newTM()) + { + // Unlikely to happen + + wrapped = true; + + } + else + { + // Else.. no worry... we will just accept the new time portion being added + // This time-mark would have been generated some time ago, so this is ok. + // tmMark is just a cache to validate the MaxIDs, so there is no need to make it atomic (synchronized) + tmMark = timePortion; + } + } + + if (wrapped) + { + // This will only happen if a computer can generate more than ID_MASK ids (16 million IDs per 16 + // milliseconds) + // If this wrapping code starts to happen, it needs revision + throw new IllegalStateException("The IDGenerator is being overlaped, and it needs revision as the system generated more than " + TimeAndCounterIDGenerator.ID_MASK + + " ids per 16 milliseconds which exceeded the IDgenerator limit"); + } + + return idReturn; + } + + public long getCurrentID() + { + return counter.get(); + } + + // for use in testcases + public long getInternalTimeMark() + { + return tmMark; + } + + // for use in testcases + public void setInternalID(final long id) + { + counter.set(tmMark | id); + } + + // for use in testcases + public void setInternalDate(final long date) + { + tmMark = (date & TimeAndCounterIDGenerator.MASK_TIME) << TimeAndCounterIDGenerator.BITS_TO_MOVE; + counter.set(tmMark); + } + + public synchronized void refresh() + { + long oldTm = tmMark; + long newTm = newTM(); + + while (newTm <= oldTm) + { + newTm = newTM(); + } + tmMark = newTm; + counter.set(tmMark); + } + + @Override + public String toString() + { + long currentCounter = counter.get(); + return "SequenceGenerator(tmMark=" + hex(tmMark) + + ", CurrentCounter = " + + currentCounter + + ", HexCurrentCounter = " + + hex(currentCounter) + + ")"; + } + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + private long newTM() + { + return (System.currentTimeMillis() & TimeAndCounterIDGenerator.MASK_TIME) << TimeAndCounterIDGenerator.BITS_TO_MOVE; + } + + private String hex(final long x) + { + return String.format("%1$X", x); + } + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiter.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiter.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiter.java new file mode 100644 index 0000000..d4ae6f7 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +/** + * This class can throttle to a specific rate, using an algorithm based on the <a + * href="http://en.wikipedia.org/wiki/Token_bucket">Token Bucket metaphor</a>. + * <p> + * The rate is specified in cycles per second (or 'Hertz'). + * @see <a href="http://en.wikipedia.org/wiki/Token_bucket">Token bucket</a> + * @author <a href="mailto:[email protected]">Tim Fox</a> + */ +public interface TokenBucketLimiter +{ + /** + * Returns the rate in cycles per second (which is the same as saying 'in Hertz'). + * @see <a href="https://en.wikipedia.org/wiki/Hertz">Hertz</a> + */ + int getRate(); + + boolean isSpin(); + + void limit(); +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiterImpl.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiterImpl.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiterImpl.java new file mode 100644 index 0000000..ac64da1 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/TokenBucketLimiterImpl.java @@ -0,0 +1,119 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.util.concurrent.TimeUnit; + +/** + * + * A TokenBucketLimiterImpl + * + * @author <a href="mailto:[email protected]">Tim Fox</a> + * + */ +public class TokenBucketLimiterImpl implements TokenBucketLimiter +{ + private final int rate; + + private final long window; + + private final boolean spin; + + /** + Even thought we don't use TokenBucket in multiThread + the implementation should keep this volatile for correctness + */ + private volatile long last; + + /** + Even thought we don't use TokenBucket in multiThread + the implementation should keep this volatile for correctness + */ + private volatile int tokens; + + public TokenBucketLimiterImpl(final int rate, final boolean spin) + { + this(rate, spin, TimeUnit.SECONDS, 1); + } + + public TokenBucketLimiterImpl(final int rate, final boolean spin, TimeUnit unit, int unitAmount) + { + this.rate = rate; + + this.spin = spin; + + this.window = unit.toMillis(unitAmount); + } + + public int getRate() + { + return rate; + } + + public boolean isSpin() + { + return spin; + } + + public void limit() + { + while (!check()) + { + if (spin) + { + Thread.yield(); + } + else + { + try + { + Thread.sleep(1); + } + catch (Exception e) + { + // Ignore + } + } + } + } + + private boolean check() + { + long now = System.currentTimeMillis(); + + if (last == 0) + { + last = now; + } + + long diff = now - last; + + if (diff >= window) + { + last = System.currentTimeMillis(); + + tokens = rate; + } + + if (tokens > 0) + { + tokens--; + + return true; + } + else + { + return false; + } + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/VersionLoader.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/VersionLoader.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/VersionLoader.java new file mode 100644 index 0000000..e7696d2 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/VersionLoader.java @@ -0,0 +1,252 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; + +import org.apache.activemq6.core.client.HornetQClientLogger; +import org.apache.activemq6.core.version.Version; +import org.apache.activemq6.core.version.impl.VersionImpl; + +/** + * This loads the version info in from a version.properties file. + * + * @author <a href="[email protected]">Andy Taylor</a> + * @author <a href="[email protected]">Clebert Suconic</a> + * @author <a href="[email protected]">Jeff Mesnil</a> + */ +public final class VersionLoader +{ + public static final String VERSION_PROP_FILE_KEY = "hornetq.version.property.filename"; + + public static final String DEFAULT_PROP_FILE_NAME = "hornetq-version.properties"; + + private static String PROP_FILE_NAME; + + private static Version[] versions; + + static + { + try + { + + try + { + PROP_FILE_NAME = AccessController.doPrivileged(new PrivilegedAction<String>() + { + public String run() + { + return System.getProperty(VersionLoader.VERSION_PROP_FILE_KEY); + } + }); + } + catch (Throwable e) + { + HornetQClientLogger.LOGGER.warn(e.getMessage(), e); + PROP_FILE_NAME = null; + } + + if (PROP_FILE_NAME == null) + { + PROP_FILE_NAME = VersionLoader.DEFAULT_PROP_FILE_NAME; + } + + VersionLoader.versions = VersionLoader.load(); + } + catch (Throwable e) + { + VersionLoader.versions = null; + HornetQClientLogger.LOGGER.error(e.getMessage(), e); + } + + } + + public static Version[] getClientVersions() + { + if (VersionLoader.versions == null) + { + throw new RuntimeException(VersionLoader.PROP_FILE_NAME + " is not available"); + } + + return VersionLoader.versions; + } + + public static Version getVersion() + { + if (VersionLoader.versions == null) + { + throw new RuntimeException(VersionLoader.PROP_FILE_NAME + " is not available"); + } + + return VersionLoader.versions[0]; + } + + public static String getClasspathString() + { + StringBuffer classpath = new StringBuffer(); + ClassLoader applicationClassLoader = VersionImpl.class.getClassLoader(); + URL[] urls = ((URLClassLoader) applicationClassLoader).getURLs(); + for (URL url : urls) + { + classpath.append(url.getFile()).append("\r\n"); + } + + return classpath.toString(); + } + + private static Version[] load() + { + Properties versionProps = new Properties(); + final InputStream in = VersionImpl.class.getClassLoader().getResourceAsStream(VersionLoader.PROP_FILE_NAME); + try + { + if (in == null) + { + HornetQClientLogger.LOGGER.noVersionOnClasspath(getClasspathString()); + throw new RuntimeException(VersionLoader.PROP_FILE_NAME + " is not available"); + } + try + { + versionProps.load(in); + String versionName = versionProps.getProperty("hornetq.version.versionName"); + int majorVersion = Integer.valueOf(versionProps.getProperty("hornetq.version.majorVersion")); + int minorVersion = Integer.valueOf(versionProps.getProperty("hornetq.version.minorVersion")); + int microVersion = Integer.valueOf(versionProps.getProperty("hornetq.version.microVersion")); + int[] incrementingVersions = parseCompatibleVersionList(versionProps.getProperty("hornetq.version.incrementingVersion")); + String versionSuffix = versionProps.getProperty("hornetq.version.versionSuffix"); + int[] compatibleVersionArray = parseCompatibleVersionList(versionProps.getProperty("hornetq.version.compatibleVersionList")); + List<Version> definedVersions = new ArrayList<Version>(incrementingVersions.length); + for (int incrementingVersion : incrementingVersions) + { + definedVersions.add(new VersionImpl(versionName, + majorVersion, + minorVersion, + microVersion, + incrementingVersion, + versionSuffix, + compatibleVersionArray)); + } + //We want the higher version to be the first + Collections.sort(definedVersions, new Comparator<Version>() + { + @Override + public int compare(Version version1, Version version2) + { + return version2.getIncrementingVersion() - version1.getIncrementingVersion(); + } + + }); + return definedVersions.toArray(new Version[incrementingVersions.length]); + } + catch (IOException e) + { + // if we get here then the messaging hasn't been built properly and the version.properties is skewed in some + // way + throw new RuntimeException("unable to load " + VersionLoader.PROP_FILE_NAME, e); + } + } + finally + { + try + { + if (in != null) + in.close(); + } + catch (Throwable ignored) + { + } + } + + } + + private static int[] parseCompatibleVersionList(String property) throws IOException + { + int[] verArray = new int[0]; + StringTokenizer tokenizer = new StringTokenizer(property, ","); + while (tokenizer.hasMoreTokens()) + { + int from = -1, to = -1; + String token = tokenizer.nextToken(); + + int cursor = 0; + char firstChar = token.charAt(0); + if (firstChar == '-') + { + // "-n" pattern + from = 0; + cursor++; + for (; cursor < token.length() && Character.isDigit(token.charAt(cursor)); cursor++) + { + // do nothing + } + if (cursor > 1) + { + to = Integer.parseInt(token.substring(1, cursor)); + } + } + else if (Character.isDigit(firstChar)) + { + for (; cursor < token.length() && Character.isDigit(token.charAt(cursor)); cursor++) + { + // do nothing + } + from = Integer.parseInt(token.substring(0, cursor)); + + if (cursor == token.length()) + { + // just "n" pattern + to = from; + } + else if (token.charAt(cursor) == '-') + { + cursor++; + if (cursor == token.length()) + { + // "n-" pattern + to = Integer.MAX_VALUE; + } + else + { + // "n-n" pattern + to = Integer.parseInt(token.substring(cursor)); + } + } + } + + if (from != -1 && to != -1) + { + // merge version array + int[] newArray = new int[verArray.length + to - from + 1]; + System.arraycopy(verArray, 0, newArray, 0, verArray.length); + for (int i = 0; i < to - from + 1; i++) + { + newArray[verArray.length + i] = from + i; + } + verArray = newArray; + } + } + + return verArray; + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XMLUtil.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XMLUtil.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XMLUtil.java new file mode 100644 index 0000000..c0f4e07 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XMLUtil.java @@ -0,0 +1,523 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq6.core.client.HornetQClientLogger; +import org.apache.activemq6.core.client.HornetQClientMessageBundle; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * @author <a href="mailto:[email protected]">Ovidiu Feodorov</a> + * @author <a href="mailto:[email protected]">Tim Fox</a> + */ +public final class XMLUtil +{ + + private XMLUtil() + { + // Utility class + } + + public static Element stringToElement(final String s) throws Exception + { + return XMLUtil.readerToElement(new StringReader(s)); + } + + public static Element urlToElement(final URL url) throws Exception + { + return XMLUtil.readerToElement(new InputStreamReader(url.openStream())); + } + + public static String readerToString(final Reader r) throws Exception + { + // Read into string + StringBuilder buff = new StringBuilder(); + int c; + while ((c = r.read()) != -1) + { + buff.append((char) c); + } + return buff.toString(); + } + + public static Element readerToElement(final Reader r) throws Exception + { + // Read into string + StringBuffer buff = new StringBuffer(); + int c; + while ((c = r.read()) != -1) + { + buff.append((char) c); + } + + // Quick hardcoded replace, FIXME this is a kludge - use regexp to match properly + String s = buff.toString(); + + StringReader sreader = new StringReader(s); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6529766 + factory.setNamespaceAware(true); + DocumentBuilder parser = factory.newDocumentBuilder(); + Document doc = parser.parse(new InputSource(sreader)); + return doc.getDocumentElement(); + } + + public static String elementToString(final Node n) + { + + String name = n.getNodeName(); + + short type = n.getNodeType(); + + if (Node.CDATA_SECTION_NODE == type) + { + return "<![CDATA[" + n.getNodeValue() + "]]>"; + } + + if (name.startsWith("#")) + { + return ""; + } + + StringBuffer sb = new StringBuffer(); + sb.append('<').append(name); + + NamedNodeMap attrs = n.getAttributes(); + if (attrs != null) + { + for (int i = 0; i < attrs.getLength(); i++) + { + Node attr = attrs.item(i); + sb.append(' ').append(attr.getNodeName()).append("=\"").append(attr.getNodeValue()).append("\""); + } + } + + String textContent = null; + NodeList children = n.getChildNodes(); + + if (children.getLength() == 0) + { + if ((textContent = XMLUtil.getTextContent(n)) != null && !"".equals(textContent)) + { + sb.append(textContent).append("</").append(name).append('>'); + } + else + { + sb.append("/>").append('\n'); + } + } + else + { + sb.append('>').append('\n'); + boolean hasValidChildren = false; + for (int i = 0; i < children.getLength(); i++) + { + String childToString = XMLUtil.elementToString(children.item(i)); + if (!"".equals(childToString)) + { + sb.append(childToString); + hasValidChildren = true; + } + } + + if (!hasValidChildren && (textContent = XMLUtil.getTextContent(n)) != null) + { + sb.append(textContent); + } + + sb.append("</").append(name).append('>'); + } + + return sb.toString(); + } + + private static final Object[] EMPTY_ARRAY = new Object[0]; + + /** + * This metod is here because Node.getTextContent() is not available in JDK 1.4 and I would like + * to have an uniform access to this functionality. + * <p> + * Note: if the content is another element or set of elements, it returns a string representation + * of the hierarchy. + * <p> + * TODO implementation of this method is a hack. Implement it properly. + */ + public static String getTextContent(final Node n) + { + if (n.hasChildNodes()) + { + StringBuffer sb = new StringBuffer(); + NodeList nl = n.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) + { + sb.append(XMLUtil.elementToString(nl.item(i))); + if (i < nl.getLength() - 1) + { + sb.append('\n'); + } + } + + String s = sb.toString(); + if (s.length() != 0) + { + return s; + } + } + + Method[] methods = Node.class.getMethods(); + + for (Method getTextContext : methods) + { + if ("getTextContent".equals(getTextContext.getName())) + { + try + { + return (String) getTextContext.invoke(n, XMLUtil.EMPTY_ARRAY); + } + catch (Exception e) + { + HornetQClientLogger.LOGGER.errorOnXMLTransform(e, n); + return null; + } + } + } + + String textContent = null; + + if (n.hasChildNodes()) + { + NodeList nl = n.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) + { + Node c = nl.item(i); + if (c.getNodeType() == Node.TEXT_NODE) + { + textContent = n.getNodeValue(); + if (textContent == null) + { + // TODO This is a hack. Get rid of it and implement this properly + String s = c.toString(); + int idx = s.indexOf("#text:"); + if (idx != -1) + { + textContent = s.substring(idx + 6).trim(); + if (textContent.endsWith("]")) + { + textContent = textContent.substring(0, textContent.length() - 1); + } + } + } + if (textContent == null) + { + break; + } + } + } + + // TODO This is a hack. Get rid of it and implement this properly + String s = n.toString(); + int i = s.indexOf('>'); + int i2 = s.indexOf("</"); + if (i != -1 && i2 != -1) + { + textContent = s.substring(i + 1, i2); + } + } + + return textContent; + } + + public static void assertEquivalent(final Node node, final Node node2) + { + if (node == null) + { + throw HornetQClientMessageBundle.BUNDLE.firstNodeNull(); + } + + if (node2 == null) + { + throw HornetQClientMessageBundle.BUNDLE.secondNodeNull(); + } + + if (!node.getNodeName().equals(node2.getNodeName())) + { + throw HornetQClientMessageBundle.BUNDLE.nodeHaveDifferentNames(); + } + + int attrCount = 0; + NamedNodeMap attrs = node.getAttributes(); + if (attrs != null) + { + attrCount = attrs.getLength(); + } + + int attrCount2 = 0; + NamedNodeMap attrs2 = node2.getAttributes(); + if (attrs2 != null) + { + attrCount2 = attrs2.getLength(); + } + + if (attrCount != attrCount2) + { + throw HornetQClientMessageBundle.BUNDLE.nodeHaveDifferentAttNumber(); + } + + outer: + for (int i = 0; i < attrCount; i++) + { + Node n = attrs.item(i); + String name = n.getNodeName(); + String value = n.getNodeValue(); + + for (int j = 0; j < attrCount; j++) + { + Node n2 = attrs2.item(j); + String name2 = n2.getNodeName(); + String value2 = n2.getNodeValue(); + + if (name.equals(name2) && value.equals(value2)) + { + continue outer; + } + } + throw HornetQClientMessageBundle.BUNDLE.attsDontMatch(name, value); + } + + boolean hasChildren = node.hasChildNodes(); + + if (hasChildren != node2.hasChildNodes()) + { + throw HornetQClientMessageBundle.BUNDLE.oneNodeHasChildren(); + } + + if (hasChildren) + { + NodeList nl = node.getChildNodes(); + NodeList nl2 = node2.getChildNodes(); + + short[] toFilter = new short[]{Node.TEXT_NODE, Node.ATTRIBUTE_NODE, Node.COMMENT_NODE}; + List<Node> nodes = XMLUtil.filter(nl, toFilter); + List<Node> nodes2 = XMLUtil.filter(nl2, toFilter); + + int length = nodes.size(); + + if (length != nodes2.size()) + { + throw HornetQClientMessageBundle.BUNDLE.nodeHasDifferentChildNumber(); + } + + for (int i = 0; i < length; i++) + { + Node n = nodes.get(i); + Node n2 = nodes2.get(i); + XMLUtil.assertEquivalent(n, n2); + } + } + } + + public static String stripCDATA(String s) + { + s = s.trim(); + if (s.startsWith("<![CDATA[")) + { + s = s.substring(9); + int i = s.indexOf("]]>"); + if (i == -1) + { + throw new IllegalStateException("argument starts with <![CDATA[ but cannot find pairing ]]>"); + } + s = s.substring(0, i); + } + return s; + } + + /* public static String replaceSystemProps(String xml) + { + Properties properties = System.getProperties(); + Enumeration e = properties.propertyNames(); + while (e.hasMoreElements()) + { + String key = (String)e.nextElement(); + String s = "${" + key + "}"; + if (xml.contains(s)) + { + xml = xml.replace(s, properties.getProperty(key)); + } + + } + return xml; + }*/ + public static String replaceSystemProps(String xml) + { + while (xml.contains("${")) + { + int start = xml.indexOf("${"); + int end = xml.indexOf("}") + 1; + if (end < 0) + { + break; + } + String subString = xml.substring(start, end); + String prop = subString.substring(2, subString.length() - 1).trim(); + String val = ""; + if (prop.contains(":")) + { + String[] parts = prop.split(":", 2); + prop = parts[0].trim(); + val = parts[1].trim(); + } + String sysProp = System.getProperty(prop, val); + HornetQClientLogger.LOGGER.debug("replacing " + subString + " with " + sysProp); + xml = xml.replace(subString, sysProp); + + } + return xml; + } + + public static long parseLong(final Node elem) + { + String value = elem.getTextContent().trim(); + + try + { + return Long.parseLong(value); + } + catch (NumberFormatException e) + { + throw HornetQClientMessageBundle.BUNDLE.mustBeLong(elem, value); + } + } + + public static int parseInt(final Node elem) + { + String value = elem.getTextContent().trim(); + + try + { + return Integer.parseInt(value); + } + catch (NumberFormatException e) + { + throw HornetQClientMessageBundle.BUNDLE.mustBeInteger(elem, value); + } + } + + public static boolean parseBoolean(final Node elem) + { + String value = elem.getTextContent().trim(); + + try + { + return Boolean.parseBoolean(value); + } + catch (NumberFormatException e) + { + throw HornetQClientMessageBundle.BUNDLE.mustBeBoolean(elem, value); + } + } + + public static double parseDouble(final Node elem) + { + String value = elem.getTextContent().trim(); + + try + { + return Double.parseDouble(value); + } + catch (NumberFormatException e) + { + throw HornetQClientMessageBundle.BUNDLE.mustBeDouble(elem, value); + } + } + + public static void validate(final Node node, final String schemaFile) throws Exception + { + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + + Schema schema = factory.newSchema(findResource(schemaFile)); + Validator validator = schema.newValidator(); + + // validate the DOM tree + try + { + validator.validate(new DOMSource(node)); + } + catch (SAXException e) + { + HornetQClientLogger.LOGGER.errorOnXMLTransformInvalidConf(e); + + throw new IllegalStateException("Invalid configuration", e); + } + } + + private static List<Node> filter(final NodeList nl, final short[] typesToFilter) + { + List<Node> nodes = new ArrayList<Node>(); + + outer: + for (int i = 0; i < nl.getLength(); i++) + { + Node n = nl.item(i); + short type = n.getNodeType(); + for (int j = 0; j < typesToFilter.length; j++) + { + if (typesToFilter[j] == type) + { + continue outer; + } + } + nodes.add(n); + } + return nodes; + } + + private static URL findResource(final String resourceName) + { + return AccessController.doPrivileged(new PrivilegedAction<URL>() + { + public URL run() + { + return ClassloadingUtil.findResource(resourceName); + } + }); + } + + + // Inner classes -------------------------------------------------------------------------------- + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/23e8edd9/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XidCodecSupport.java ---------------------------------------------------------------------- diff --git a/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XidCodecSupport.java b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XidCodecSupport.java new file mode 100644 index 0000000..00ec960 --- /dev/null +++ b/activemq6-core-client/src/main/java/org/apache/activemq6/utils/XidCodecSupport.java @@ -0,0 +1,70 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat 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.activemq6.utils; + +import javax.transaction.xa.Xid; + +import org.apache.activemq6.api.core.HornetQBuffer; +import org.apache.activemq6.core.transaction.impl.XidImpl; + +/** + * @author <a href="mailto:[email protected]">Jeff Mesnil</a> + * + * + */ +public class XidCodecSupport +{ + + // Constants ----------------------------------------------------- + + // Attributes ---------------------------------------------------- + + // Static -------------------------------------------------------- + + public static void encodeXid(final Xid xid, final HornetQBuffer out) + { + out.writeInt(xid.getFormatId()); + out.writeInt(xid.getBranchQualifier().length); + out.writeBytes(xid.getBranchQualifier()); + out.writeInt(xid.getGlobalTransactionId().length); + out.writeBytes(xid.getGlobalTransactionId()); + } + + public static Xid decodeXid(final HornetQBuffer in) + { + int formatID = in.readInt(); + byte[] bq = new byte[in.readInt()]; + in.readBytes(bq); + byte[] gtxid = new byte[in.readInt()]; + in.readBytes(gtxid); + Xid xid = new XidImpl(bq, formatID, gtxid); + return xid; + } + + public static int getXidEncodeLength(final Xid xid) + { + return DataConstants.SIZE_INT * 3 + xid.getBranchQualifier().length + xid.getGlobalTransactionId().length; + } + + // Constructors -------------------------------------------------- + + // Public -------------------------------------------------------- + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + // Inner classes ------------------------------------------------- +}
