diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2010-01-31 00:31:49 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2010-01-31 00:31:49 +0000 |
commit | 5efcd04d4557a6902a3ba85aa5114b0f282937f5 (patch) | |
tree | 78968a239c7971d203895ddc1c69a54b1b14ef76 | |
parent | 7c27a4488fb09b2898c2a3a017f7e86c834abe28 (diff) | |
download | qpid-python-5efcd04d4557a6902a3ba85aa5114b0f282937f5.tar.gz |
QPID-2379 : Initial work on adding QMF and federation to the Java Broker
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@904934 13f79535-47bb-0310-9956-ffa450edef68
188 files changed, 14786 insertions, 2468 deletions
diff --git a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java index 637997a947..b497f192d6 100644 --- a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java +++ b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java @@ -28,12 +28,17 @@ import javax.management.openmbean.OpenDataException; import javax.management.openmbean.TabularData; import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.AbstractExchange; +import org.apache.qpid.server.exchange.AbstractExchangeMBean; +import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.junit.extensions.util.SizeOf; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; @@ -69,7 +74,7 @@ public class DiagnosticExchange extends AbstractExchange * MBean class implementing the management interfaces. */ @MBeanDescription("Management Bean for Diagnostic Exchange") - private final class DiagnosticExchangeMBean extends ExchangeMBean + private final class DiagnosticExchangeMBean extends AbstractExchangeMBean<DiagnosticExchange> { /** @@ -80,8 +85,8 @@ public class DiagnosticExchange extends AbstractExchange @MBeanConstructor("Creates an MBean for AMQ Diagnostic exchange") public DiagnosticExchangeMBean() throws JMException { - super(); - _exchangeType = "diagnostic"; + super(DiagnosticExchange.this); + init(); } @@ -116,6 +121,42 @@ public class DiagnosticExchange extends AbstractExchange } // End of MBean class + + public static final ExchangeType<DiagnosticExchange> TYPE = new ExchangeType<DiagnosticExchange>() + { + + public AMQShortString getName() + { + return DIAGNOSTIC_EXCHANGE_CLASS; + } + + public Class<DiagnosticExchange> getExchangeClass() + { + return DiagnosticExchange.class; + } + + public DiagnosticExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + DiagnosticExchange exch = new DiagnosticExchange(); + exch.initialise(host,name,durable,ticket,autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return DIAGNOSTIC_EXCHANGE_NAME ; + } + }; + + public DiagnosticExchange() + { + super(TYPE); + } + /** * Creates a new MBean instance * @@ -123,7 +164,7 @@ public class DiagnosticExchange extends AbstractExchange * @throws AMQException * if something goes wrong */ - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { return new DiagnosticExchange.DiagnosticExchangeMBean(); @@ -134,51 +175,12 @@ public class DiagnosticExchange extends AbstractExchange return _logger; } - public AMQShortString getType() - { - return DIAGNOSTIC_EXCHANGE_CLASS; - } - - /** - * Does nothing. - * - * @param routingKey - * pointless - * @param queue - * pointless - * @param args - * pointless - * @throws AMQException - * never - */ - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - // No op - } - public void registerQueue(String routingKey, AMQQueue queue, Map<String, Object> args) throws AMQException { // No op } - /** - * Does nothing. - * - * @param routingKey - * pointless - * @param queue - * pointless - * @param args - * pointless - * @throws AMQException - * never - */ - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - // No op - } - public boolean isBound(AMQShortString routingKey, AMQQueue queue) { return false; @@ -199,7 +201,7 @@ public class DiagnosticExchange extends AbstractExchange return false; } - public ArrayList<AMQQueue> route(InboundMessage payload) + public ArrayList<AMQQueue> doRoute(InboundMessage payload) { Long value = new Long(SizeOf.getUsedMemory()); @@ -224,4 +226,14 @@ public class DiagnosticExchange extends AbstractExchange return false; } + + protected void onBind(final Binding binding) + { + + } + + protected void onUnbind(final Binding binding) + { + + } } diff --git a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java index cb46b9c815..ace30b9b89 100644 --- a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java +++ b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java @@ -21,18 +21,25 @@ package org.apache.qpid.extras.exchanges.example; */ -import java.util.List; -import java.util.Map; -import java.util.ArrayList; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ExchangeConfigType; +import org.apache.qpid.server.configuration.VirtualHostConfig; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeReferrer; +import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.InboundMessage; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.UUID; public class TestExchange implements Exchange { @@ -41,21 +48,24 @@ public class TestExchange implements Exchange { } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + + + public void addBindingListener(final BindingListener listener) { + //To change body of implemented methods use File | Settings | File Templates. } - public Map<AMQShortString, List<AMQQueue>> getBindings() + public void removeBindingListener(final BindingListener listener) { - return null; + //To change body of implemented methods use File | Settings | File Templates. } - public AMQShortString getName() + public AMQShortString getNameShortString() { return null; } - public AMQShortString getType() + public AMQShortString getTypeShortString() { return null; } @@ -75,11 +85,61 @@ public class TestExchange implements Exchange return false; } + public void addCloseTask(final Task task) + { + + } + + public void removeCloseTask(final Task task) + { + + } + public Exchange getAlternateExchange() { return null; } + public Map<String, Object> getArguments() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getBindingCount() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getBindingCountHigh() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getMsgReceives() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getMsgRoutes() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getByteReceives() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getByteRoutes() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public long getCreateTime() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + public void setAlternateExchange(Exchange exchange) { @@ -100,11 +160,41 @@ public class TestExchange implements Exchange return false; } + public void addBinding(final Binding binding) + { + + } + + public void removeBinding(final Binding binding) + { + + } + + public Collection<Binding> getBindings() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public void initialise(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete) throws AMQException { } + public VirtualHostConfig getVirtualHost() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public String getName() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public ExchangeType getType() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public boolean isAutoDelete() { return false; @@ -130,16 +220,27 @@ public class TestExchange implements Exchange return false; } - public boolean isDurable() + public UUID getId() { - return false; + return null; //To change body of implemented methods use File | Settings | File Templates. } - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public ExchangeConfigType getConfigType() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public ConfiguredObject getParent() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isDurable() + { + return false; } - public ArrayList<AMQQueue> route(InboundMessage message) + public ArrayList<? extends BaseQueue> route(InboundMessage message) { return new ArrayList<AMQQueue>(); } diff --git a/qpid/java/broker/build.xml b/qpid/java/broker/build.xml index ae133d1a96..c6da59234c 100644 --- a/qpid/java/broker/build.xml +++ b/qpid/java/broker/build.xml @@ -28,6 +28,11 @@ <property name="output.dir" value="${module.precompiled}/org/apache/qpid/server/filter/jms/selector"/> + <property name="qmf.input.file" value="${project.root}/../specs/management-schema.xml"/> + <property name="qmf.xsl.file" value="${project.root}/broker/src/xsl/qmf.xsl"/> + <property name="qmf.output.dir" value="${module.precompiled}/org/apache/qpid/server/qmf/schema"/> + <property name="qmf.output.file" value="BrokerSchema.java"/> + <property name="gentools.home" location="${project.root}/../gentools" /> <property name="generated.package" value="org/apache/qpid/server/logging/messages" /> <property name="generated.dir" location="${module.precompiled}/${generated.package}" /> @@ -35,7 +40,7 @@ <property name="velocity.timestamp" location="${generated.dir}/velocity.timestamp" /> - <target name="precompile" depends="gen_logging"> + <target name="precompile" depends="gen_logging,gen_qmf"> <mkdir dir="${output.dir}"/> <!-- Compile Selcector Code --> <javacc target="src/main/grammar/SelectorParser.jj" @@ -82,6 +87,16 @@ <touch file="${velocity.timestamp}" /> </target> + <target name="check_qmf_deps"> + <uptodate property="gen_qmf.notRequired" targetfile="${qmf.output.dir}/${qmf.output.file}"> + <srcfiles file="${qmf.input.file}"/> + <srcfiles file="${qmf.xsl.file}"/> + </uptodate> + </target> + + <target name="gen_qmf" depends="check_qmf_deps" unless="gen_qmf.notRequired"> + <xslt in="${qmf.input.file}" out="${qmf.output.dir}/${qmf.output.file}" style="${qmf.xsl.file}"/> + </target> <target name="copy-etc-release" if="module.etc.exists" description="copy etc directory if it exists to build tree"> <copy todir="${module.release}/etc" failonerror="false" flatten="true"> diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java new file mode 100644 index 0000000000..706ab3974a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/CompletionCode.java @@ -0,0 +1,36 @@ +/* + * + * 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.qpid.qmf; + +public enum CompletionCode +{ + OK, + UNKNOWN_OBJECT, + UNKNOWN_METHOD, + NOT_IMPLEMENTED, + INVALID_PARAMETER, + FEATURE_NOT_IMPLEMENTED, + FORBIDDEN, + EXCEPTION, + UNKNOWN_PACKAGE, + UNKNOWN_CLASS; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java new file mode 100644 index 0000000000..b639cb9fc1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -0,0 +1,559 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ExchangeConfigType; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeReferrer; +import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.exchange.topic.TopicBinding; +import org.apache.qpid.server.exchange.topic.TopicExchangeResult; +import org.apache.qpid.server.exchange.topic.TopicMatcherResult; +import org.apache.qpid.server.exchange.topic.TopicNormalizer; +import org.apache.qpid.server.exchange.topic.TopicParser; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; + +public class ManagementExchange implements Exchange, QMFService.Listener +{ + private static final AMQShortString QPID_MANAGEMENT = new AMQShortString("qpid.management"); + private static final AMQShortString QPID_MANAGEMENT_TYPE = new AMQShortString("management"); + + private VirtualHost _virtualHost; + + private final TopicParser _parser = new TopicParser(); + + private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults = + new ConcurrentHashMap<AMQShortString, TopicExchangeResult>(); + + private final Map<TopicBinding, FieldTable> _topicBindings = new HashMap<TopicBinding, FieldTable>(); + private final Set<Binding> _bindingSet = new HashSet<Binding>(); + private UUID _id; + private static final String AGENT_BANK = "0"; + + private int _bindingCountHigh; + private final AtomicLong _msgReceived = new AtomicLong(); + private final AtomicLong _bytesReceived = new AtomicLong(); + + private final CopyOnWriteArrayList<BindingListener> _listeners = new CopyOnWriteArrayList<Exchange.BindingListener>(); + + // TODO + private long _createTime = System.currentTimeMillis(); + + + private class ManagementQueue implements BaseQueue + { + private final String NAME_AS_STRING = "##__mgmt_pseudo_queue__##" + UUID.randomUUID().toString(); + private final AMQShortString NAME_AS_SHORT_STRING = new AMQShortString(NAME_AS_STRING); + + public void enqueue(ServerMessage message) throws AMQException + { + AMQMessageHeader h = message.getMessageHeader(); + long size = message.getSize(); + + ByteBuffer buf = ByteBuffer.allocate((int) size); + + int offset = 0; + + while(offset < size) + { + offset += message.getContent(buf,offset); + } + + buf.flip(); + QMFCommandDecoder commandDecoder = new QMFCommandDecoder(getQMFService(),buf); + QMFCommand cmd; + while((cmd = commandDecoder.decode()) != null) + { + cmd.process(_virtualHost, message); + } + + } + + public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException + { + enqueue(message); + } + + public boolean isDurable() + { + return false; + } + + public AMQShortString getNameShortString() + { + return NAME_AS_SHORT_STRING; + } + + public String getResourceName() + { + return NAME_AS_STRING; + } + } + + + private final ManagementQueue _mgmtQueue = new ManagementQueue(); + + public ManagementExchange() + { + } + + public static final ExchangeType<ManagementExchange> TYPE = new ExchangeType<ManagementExchange>() + { + + public AMQShortString getName() + { + return QPID_MANAGEMENT_TYPE; + } + + public Class<ManagementExchange> getExchangeClass() + { + return ManagementExchange.class; + } + + public ManagementExchange newInstance(VirtualHost host, + AMQShortString name, + boolean durable, + int ticket, + boolean autoDelete) throws AMQException + { + ManagementExchange exch = new ManagementExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); + return exch; + } + + public AMQShortString getDefaultExchangeName() + { + return QPID_MANAGEMENT; + } + }; + + + public AMQShortString getNameShortString() + { + return QPID_MANAGEMENT; + } + + public AMQShortString getTypeShortString() + { + return QPID_MANAGEMENT_TYPE; + } + + public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) + throws AMQException + { + if(!QPID_MANAGEMENT.equals(name)) + { + throw new AMQException("Can't create more than one Management exchange"); + } + _virtualHost = host; + _id = host.getConfigStore().createId(); + _virtualHost.scheduleTask(_virtualHost.getBroker().getManagementPublishInterval(),_updateTask); + getConfigStore().addConfiguredObject(this); + getQMFService().addListener(this); + } + + public UUID getId() + { + return _id; + } + + public ExchangeConfigType getConfigType() + { + return ExchangeConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _virtualHost; + } + + public boolean isDurable() + { + return true; + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public String getName() + { + return QPID_MANAGEMENT.toString(); + } + + public ExchangeType getType() + { + return TYPE; + } + + public boolean isAutoDelete() + { + return false; + } + + public int getTicket() + { + return 0; + } + + public void close() throws AMQException + { + getConfigStore().removeConfiguredObject(this); + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public synchronized void addBinding(final Binding b) + { + + _bindingSet.add(b); + + for(BindingListener listener : _listeners) + { + listener.bindingAdded(this, b); + } + + if(_bindingSet.size() > _bindingCountHigh) + { + _bindingCountHigh = _bindingSet.size(); + } + + TopicBinding binding = new TopicBinding(new AMQShortString(b.getBindingKey()), b.getQueue(), null); + + if(!_topicBindings.containsKey(binding)) + { + AMQShortString routingKey = TopicNormalizer.normalize(new AMQShortString(b.getBindingKey())); + + TopicExchangeResult result = _topicExchangeResults.get(routingKey); + if(result == null) + { + result = new TopicExchangeResult(); + result.addUnfilteredQueue(b.getQueue()); + _parser.addBinding(routingKey, result); + _topicExchangeResults.put(routingKey,result); + } + else + { + result.addUnfilteredQueue(b.getQueue()); + } + _topicBindings.put(binding, null); + + + } + String bindingKey = b.getBindingKey(); + + if(bindingKey.startsWith("schema.") || bindingKey.startsWith("*.") || bindingKey.startsWith("#.")) + { + publishAllSchema(); + } + if(bindingKey.startsWith("console.") || bindingKey.startsWith("*.") || bindingKey.startsWith("#.")) + { + publishAllConsole(); + } + + } + + void publishAllConsole() + { + QMFService qmfService = getQMFService(); + + long sampleTime = System.currentTimeMillis(); + + for(QMFPackage pkg : qmfService.getSupportedSchemas()) + { + for(QMFClass qmfClass : pkg.getClasses()) + { + Collection<QMFObject> qmfObjects = qmfService.getObjects(qmfClass); + + publishObjectsToConsole(sampleTime, qmfObjects); + } + + } + + } + + private QMFService getQMFService() + { + return _virtualHost.getApplicationRegistry().getQMFService(); + } + + void publishObjectsToConsole(final long sampleTime, + final Collection<QMFObject> qmfObjects) + { + if(!qmfObjects.isEmpty() && hasBindings()) + { + QMFClass qmfClass = qmfObjects.iterator().next().getQMFClass(); + ArrayList<QMFCommand> commands = new ArrayList<QMFCommand>(); + + + for(QMFObject obj : qmfObjects) + { + commands.add(obj.asConfigInfoCmd(sampleTime)); + commands.add(obj.asInstrumentInfoCmd(sampleTime)); + } + + publishToConsole(qmfClass, commands); + } + } + + private void publishToConsole(final QMFClass qmfClass, final ArrayList<QMFCommand> commands) + { + if(!commands.isEmpty() && hasBindings()) + { + String routingKey = "console.obj.1." + AGENT_BANK + "." + qmfClass.getPackage().getName() + "." + qmfClass.getName(); + QMFMessage message = new QMFMessage(routingKey,commands.toArray(new QMFCommand[commands.size()])); + + Collection<TopicMatcherResult> results = _parser.parse(new AMQShortString(routingKey)); + HashSet<AMQQueue> queues = new HashSet<AMQQueue>(); + for(TopicMatcherResult result : results) + { + queues.addAll(((TopicExchangeResult)result).getUnfilteredQueues()); + } + for(AMQQueue queue : queues) + { + try + { + queue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + } + } + + void publishAllSchema() + { + + } + + public synchronized void removeBinding(final Binding binding) + { + _bindingSet.remove(binding); + + TopicBinding topicBinding = new TopicBinding(new AMQShortString(binding.getBindingKey()), binding.getQueue(), null); + + if(_topicBindings.containsKey(topicBinding)) + { + AMQShortString bindingKey = TopicNormalizer.normalize(topicBinding.getBindingKey()); + TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + result.removeUnfilteredQueue(binding.getQueue()); + } + + for(BindingListener listener : _listeners) + { + listener.bindingRemoved(this, binding); + } + } + + public synchronized Collection<Binding> getBindings() + { + return new ArrayList<Binding>(_bindingSet); + } + + public ArrayList<BaseQueue> route(InboundMessage message) + { + ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(1); + _msgReceived.incrementAndGet(); + _bytesReceived.addAndGet(message.getSize()); + queues.add(_mgmtQueue); + return queues; + } + + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(AMQShortString routingKey, AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(AMQShortString routingKey) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean hasBindings() + { + return !_bindingSet.isEmpty(); + } + + public boolean isBound(String bindingKey, AMQQueue queue) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isBound(String bindingKey) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public void addCloseTask(final Task task) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeCloseTask(final Task task) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + + + public Exchange getAlternateExchange() + { + return null; + } + + public Map<String, Object> getArguments() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setAlternateExchange(Exchange exchange) + { + + } + + public void removeReference(ExchangeReferrer exchange) + { + } + + public void addReference(ExchangeReferrer exchange) + { + } + + public boolean hasReferrers() + { + return true; + } + + + + private final TimerTask _updateTask = new UpdateTask(); + + + private class UpdateTask extends TimerTask + { + + public void run() + { + publishAllConsole(); + publishAllSchema(); + + } + + } + + public void objectCreated(final QMFObject obj) + { + publishObjectsToConsole(System.currentTimeMillis(), Collections.singleton(obj)); + } + + public void objectDeleted(final QMFObject obj) + { + publishObjectsToConsole(System.currentTimeMillis(), Collections.singleton(obj)); + } + + public long getBindingCount() + { + return getBindings().size(); + } + + public long getBindingCountHigh() + { + return _bindingCountHigh; + } + + public long getMsgReceives() + { + return _msgReceived.get(); + } + + public long getMsgRoutes() + { + return getMsgReceives(); + } + + public long getByteReceives() + { + return _bytesReceived.get(); + } + + public long getByteRoutes() + { + return getByteReceives(); + } + + public long getCreateTime() + { + return _createTime; + } + + public void addBindingListener(final BindingListener listener) + { + _listeners.add(listener); + } + + public void removeBindingListener(final BindingListener listener) + { + _listeners.remove(listener); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java new file mode 100644 index 0000000000..b98daf7cb1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java @@ -0,0 +1,78 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.transport.codec.BBEncoder; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.AMQException; +import org.apache.qpid.management.common.mbeans.ManagedConnection; + +import java.util.ArrayList; + +public class QMFBrokerRequestCommand extends QMFCommand +{ + + public QMFBrokerRequestCommand(QMFCommandHeader header, BBDecoder buf) + { + super(header); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String queueName = message.getMessageHeader().getReplyToRoutingKey(); + + QMFCommand[] commands = new QMFCommand[2]; + commands[0] = new QMFBrokerResponseCommand(this, virtualHost); + commands[1] = new QMFCommandCompletionCommand(this); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + for(QMFCommand cmd : commands) + { + QMFMessage responseMessage = new QMFMessage(queueName, cmd); + + + ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java new file mode 100644 index 0000000000..ac01c47fe8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerResponseCommand.java @@ -0,0 +1,46 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFBrokerResponseCommand extends QMFCommand +{ + private QMFCommandHeader _header; + private VirtualHost _virtualHost; + + public QMFBrokerResponseCommand(QMFBrokerRequestCommand qmfBrokerRequestCommand, VirtualHost virtualHost) + { + super( new QMFCommandHeader(qmfBrokerRequestCommand.getHeader().getVersion(), + qmfBrokerRequestCommand.getHeader().getSeq(), + QMFOperation.BROKER_RESPONSE)); + _virtualHost = virtualHost; + } + + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUuid(_virtualHost.getBrokerId()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java new file mode 100644 index 0000000000..3408ff09f4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClass.java @@ -0,0 +1,158 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.configuration.ConfiguredObject; + +import java.util.Collection; +import java.util.Map; +import java.util.List; +import java.util.LinkedHashMap; + +abstract public class QMFClass +{ + + + public enum Type + { + OBJECT((byte)1), + EVENT((byte)2); + + private final byte _value; + + Type(byte value) + { + _value = value; + } + + public byte getValue() + { + return _value; + } + } + + private final Type _type; + private QMFPackage _package; + private final String _name; + private byte[] _schemaHash; + + private Map<String, QMFProperty> _properties = new LinkedHashMap<String, QMFProperty>(); + private Map<String, QMFStatistic> _statistics = new LinkedHashMap<String, QMFStatistic>(); + private Map<String, QMFMethod> _methods = new LinkedHashMap<String, QMFMethod>(); + + + + public QMFClass(Type type, String name, byte[] schemaHash, List<QMFProperty> properties, + List<QMFStatistic> statistics, List<QMFMethod> methods) + { + this(type, name, schemaHash); + setProperties(properties); + setStatistics(statistics); + setMethods(methods); + } + + + public QMFClass(Type type, String name, byte[] schemaHash) + + { + _type = type; + _name = name; + _schemaHash = schemaHash; + + } + + protected void setProperties(List<QMFProperty> properties) + { + for(QMFProperty prop : properties) + { + _properties.put(prop.getName(), prop); + } + } + + protected void setStatistics(List<QMFStatistic> statistics) + { + for(QMFStatistic stat : statistics) + { + _statistics.put(stat.getName(), stat); + } + } + + + protected void setMethods(List<QMFMethod> methods) + { + for(QMFMethod method : methods) + { + _methods.put(method.getName(), method); + } + } + + public void setPackage(QMFPackage aPackage) + { + _package = aPackage; + for(QMFProperty prop : _properties.values()) + { + prop.setQMFClass(this); + } + // TODO Statisics, Methods + } + + public Type getType() + { + return _type; + } + + public QMFPackage getPackage() + { + return _package; + } + + public String getName() + { + return _name; + } + + public byte[] getSchemaHash() + { + return _schemaHash; + } + + public Collection<QMFProperty> getProperties() + { + return _properties.values(); + } + + public Collection<QMFStatistic> getStatistics() + { + return _statistics.values(); + } + + public Collection<QMFMethod> getMethods() + { + return _methods.values(); + } + + public QMFMethod getMethod(String methodName) + { + return _methods.get(methodName); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java new file mode 100644 index 0000000000..a956a9bd70 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassIndicationCommand.java @@ -0,0 +1,50 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFClassIndicationCommand extends QMFCommand +{ + private QMFClass _qmfClass; + + public QMFClassIndicationCommand(QMFClassQueryCommand qmfClassQueryCommand, QMFClass qmfClass) + { + super(new QMFCommandHeader(qmfClassQueryCommand.getHeader().getVersion(), + qmfClassQueryCommand.getHeader().getSeq(), + QMFOperation.CLASS_INDICATION)); + _qmfClass = qmfClass; + } + + + @Override + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUint8(_qmfClass.getType().getValue()); + encoder.writeStr8(_qmfClass.getPackage().getName()); + encoder.writeStr8(_qmfClass.getName()); + encoder.writeBin128(_qmfClass.getSchemaHash()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java new file mode 100644 index 0000000000..26a27cfa19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java @@ -0,0 +1,90 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.AMQException; + +import java.util.ArrayList; +import java.util.Collection; + +public class QMFClassQueryCommand extends QMFCommand +{ + private final String _package; + + public QMFClassQueryCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + _package = decoder.readStr8(); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + QMFPackage qmfPackage = service.getPackage(_package); + Collection<QMFClass> qmfClasses = qmfPackage.getClasses(); + + QMFCommand[] commands = new QMFCommand[ qmfClasses.size() + 1 ]; + + int i = 0; + for(QMFClass qmfClass : qmfClasses) + { + commands[i++] = new QMFClassIndicationCommand(this, qmfClass); + } + commands[ commands.length - 1 ] = new QMFCommandCompletionCommand(this); + + + for(QMFCommand cmd : commands) + { + + + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java new file mode 100644 index 0000000000..4f143701af --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommand.java @@ -0,0 +1,54 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.codec.BBEncoder; + +public abstract class QMFCommand +{ + + private final QMFCommandHeader _header; + + protected QMFCommand(QMFCommandHeader header) + { + _header = header; + } + + + public void process(final VirtualHost virtualHost, final ServerMessage message) + { + throw new UnsupportedOperationException(); + } + + public void encode(BBEncoder encoder) + { + _header.encode(encoder); + + } + + public QMFCommandHeader getHeader() + { + return _header; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java new file mode 100644 index 0000000000..f163e434d1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java @@ -0,0 +1,56 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFCommandCompletionCommand extends QMFCommand +{ + + private final CompletionCode _status; + private final String _text; + + public QMFCommandCompletionCommand(QMFCommand command) + { + this(command, CompletionCode.OK, ""); + } + public QMFCommandCompletionCommand(QMFCommand command, CompletionCode status, String text) + { + super( new QMFCommandHeader(command.getHeader().getVersion(), + command.getHeader().getSeq(), + QMFOperation.COMMAND_COMPLETION)); + + _status = status; + _text = text; + } + + + @Override + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeInt32(_status.ordinal()); + encoder.writeStr8(_text); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java new file mode 100644 index 0000000000..ac036dfa19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandDecoder.java @@ -0,0 +1,98 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; + +import java.nio.ByteBuffer; + +public class QMFCommandDecoder +{ + private BBDecoder _decoder; + + + private static final QMFOperation[] OP_CODES = new QMFOperation[256]; + private final QMFService _qmfService; + + static + { + for(QMFOperation op : QMFOperation.values()) + { + OP_CODES[op.getOpcode()] = op; + } + } + + public QMFCommandDecoder(final QMFService qmfService, ByteBuffer buf) + { + _qmfService = qmfService; + _decoder = new BBDecoder(); + _decoder.init(buf); + } + + public QMFCommand decode() + { + if(_decoder.hasRemaining()) + { + QMFCommandHeader header = readQMFHeader(); + + switch(header.getOperation()) + { + case BROKER_REQUEST: + return new QMFBrokerRequestCommand(header, _decoder); + case PACKAGE_QUERY: + return new QMFPackageQueryCommand(header, _decoder); + case CLASS_QUERY: + return new QMFClassQueryCommand(header, _decoder); + case SCHEMA_REQUEST: + return new QMFSchemaRequestCommand(header, _decoder); + case METHOD_REQUEST: + return new QMFMethodRequestCommand(header, _decoder, _qmfService); + case GET_QUERY: + return new QMFGetQueryCommand(header, _decoder); + default: + System.out.println("Unknown command"); + + } + + return null; + } + else + { + return null; + } + } + + private QMFCommandHeader readQMFHeader() + { + if(_decoder.readInt8() == (byte) 'A' + && _decoder.readInt8() == (byte) 'M') + { + byte version = _decoder.readInt8(); + short opCode = _decoder.readUint8(); + int seq = _decoder.readInt32(); + + return new QMFCommandHeader(version, seq, OP_CODES[opCode]); + + } + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java new file mode 100644 index 0000000000..c4d771317f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandHeader.java @@ -0,0 +1,63 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFCommandHeader +{ + private final byte _version; + private final int _seq; + + private final QMFOperation _operation; + + public QMFCommandHeader(byte version, int seq, QMFOperation operation) + { + _version = version; + _seq = seq; + _operation = operation; + } + + public byte getVersion() + { + return _version; + } + + public int getSeq() + { + return _seq; + } + + public QMFOperation getOperation() + { + return _operation; + } + + public void encode(BBEncoder encoder) + { + encoder.writeUint8((short)'A'); + encoder.writeUint8((short)'M'); + encoder.writeInt8(_version); + encoder.writeUint8((short)_operation.getOpcode()); + encoder.writeInt32(_seq); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java new file mode 100644 index 0000000000..ec471f18e8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventClass.java @@ -0,0 +1,42 @@ +/* + * + * 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.qpid.qmf; + +import java.util.List; + +public abstract class QMFEventClass extends QMFClass +{ + public QMFEventClass(String name, + byte[] schemaHash, + List<QMFProperty> properties, + List<QMFStatistic> statistics, List<QMFMethod> methods) + { + super(Type.EVENT, name, schemaHash, properties, statistics, methods); + } + + public QMFEventClass(String name, byte[] schemaHash) + { + super(Type.EVENT, name, schemaHash); + } + + abstract public QMFEventSeverity getSeverity(); + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java new file mode 100644 index 0000000000..d70c12db19 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventCommand.java @@ -0,0 +1,49 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public abstract class QMFEventCommand<T extends QMFEventClass> extends QMFCommand +{ + private final long _timestamp; + + protected QMFEventCommand() + { + super(new QMFCommandHeader((byte)'2',0, QMFOperation.EVENT)); + _timestamp = System.currentTimeMillis(); + } + + abstract public T getEventClass(); + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + encoder.writeStr8(getEventClass().getPackage().getName()); + encoder.writeStr8(getEventClass().getName()); + encoder.writeBin128(new byte[16]); + encoder.writeUint64(_timestamp * 1000000L); + encoder.writeUint8((short) getEventClass().getSeverity().ordinal()); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java new file mode 100644 index 0000000000..9f9c832732 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFEventSeverity.java @@ -0,0 +1,33 @@ +/* + * + * 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.qpid.qmf; + +public enum QMFEventSeverity +{ + EMERGENCY, + ALERT, + CRITICAL, + ERROR, + WARN, + NOTICE, + INFORM, + DEBUG +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java new file mode 100644 index 0000000000..8e8cb55a0d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java @@ -0,0 +1,182 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.AMQException; + +import java.util.*; + +public class QMFGetQueryCommand extends QMFCommand +{ + private Map<String, Object> _map; + + + public QMFGetQueryCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + + _map = decoder.readMap(); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + String className = (String) _map.get("_class"); + String packageName = (String) _map.get("_package"); + byte[] objectIdBytes = (byte[]) _map.get("_objectId"); + UUID objectId; + if(objectIdBytes != null) + { + long msb = 0; + long lsb = 0; + + for (int i = 0; i != 8; i++) + { + msb = (msb << 8) | (objectIdBytes[i] & 0xff); + } + for (int i = 8; i != 16; i++) + { + lsb = (lsb << 8) | (objectIdBytes[i] & 0xff); + } + objectId = new UUID(msb, lsb); + } + else + { + objectId = null; + } + + List<QMFCommand> commands = new ArrayList<QMFCommand>(); + final long sampleTime = System.currentTimeMillis() * 1000000l; + + Collection<QMFPackage> packages; + + if(packageName != null && packageName.length() != 0) + { + QMFPackage qmfPackage = service.getPackage(packageName); + if(qmfPackage == null) + { + packages = Collections.EMPTY_LIST; + } + else + { + packages = Collections.singleton(qmfPackage); + } + } + else + { + packages = service.getSupportedSchemas(); + } + + for(QMFPackage qmfPackage : packages) + { + + Collection<QMFClass> qmfClasses; + + if(className != null && className.length() != 0) + { + QMFClass qmfClass = qmfPackage.getQMFClass(className); + if(qmfClass == null) + { + qmfClasses = Collections.EMPTY_LIST; + } + else + { + qmfClasses = Collections.singleton(qmfClass); + } + } + else + { + qmfClasses = qmfPackage.getClasses(); + } + + + for(QMFClass qmfClass : qmfClasses) + { + Collection<QMFObject> objects; + + if(objectId != null) + { + QMFObject obj = service.getObjectById(qmfClass, objectId); + if(obj == null) + { + objects = Collections.EMPTY_LIST; + } + else + { + objects = Collections.singleton(obj); + } + } + else + { + objects = service.getObjects(qmfClass); + } + + for(QMFObject object : objects) + { + + commands.add(object.asGetQueryResponseCmd(this, sampleTime)); + } + } + + + } + + + commands.add( new QMFCommandCompletionCommand(this)); + + + for(QMFCommand cmd : commands) + { + + + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java new file mode 100644 index 0000000000..c250b2c011 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java @@ -0,0 +1,205 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.message.*; +import org.apache.qpid.transport.codec.BBEncoder; + +import java.nio.ByteBuffer; +import java.util.Set; + +public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHeader +{ + + private ByteBuffer _content; + private String _routingKey; + + public QMFMessage(String routingKey, QMFCommand command) + { + this(routingKey, new QMFCommand[] { command }); + } + + + public QMFMessage(String routingKey, QMFCommand[] commands) + { + _routingKey = routingKey; + BBEncoder encoder = new BBEncoder(256); + + for(QMFCommand cmd : commands) + { + cmd.encode(encoder); + } + + + _content = encoder.buffer(); + } + + public String getRoutingKey() + { + return _routingKey; + } + + public AMQMessageHeader getMessageHeader() + { + return this; + } + + public boolean isPersistent() + { + return false; + } + + public boolean isRedelivered() + { + return false; + } + + public long getSize() + { + return _content.limit(); + } + + public boolean isImmediate() + { + return false; + } + + public String getCorrelationId() + { + return null; + } + + public long getExpiration() + { + return 0; + } + + public String getMessageId() + { + return null; + } + + public String getMimeType() + { + return null; + } + + public String getEncoding() + { + return null; + } + + public byte getPriority() + { + return 4; + } + + public long getTimestamp() + { + return 0; + } + + public String getType() + { + return null; + } + + public String getReplyTo() + { + return null; + } + + public String getReplyToExchange() + { + return null; + } + + public String getReplyToRoutingKey() + { + return null; + } + + public Object getHeader(String name) + { + return null; + } + + public boolean containsHeaders(Set<String> names) + { + return false; + } + + public boolean containsHeader(String name) + { + return false; + } + + public MessageReference newReference() + { + return new QMFMessageReference(this); + } + + public Long getMessageNumber() + { + return null; + } + + public long getArrivalTime() + { + return 0; + } + + public int getContent(ByteBuffer buf, int offset) + { + ByteBuffer src = _content.duplicate(); + _content.position(offset); + _content = _content.slice(); + int len = _content.remaining(); + if(len > buf.remaining()) + { + len = buf.remaining(); + } + + buf.put(src); + + return len; + } + + private class QMFMessageReference extends MessageReference<QMFMessage> + { + public QMFMessageReference(QMFMessage message) + { + super(message); + } + + protected void onReference(QMFMessage message) + { + + } + + protected void onRelease(QMFMessage message) + { + + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java new file mode 100644 index 0000000000..63e8fa6a1e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethod.java @@ -0,0 +1,157 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.Encoder; +import org.apache.qpid.transport.codec.BBDecoder; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ArrayList; + +public abstract class QMFMethod<T extends QMFObject> +{ + private final LinkedHashMap<String,Object> _map = new LinkedHashMap<String,Object>(); + private final List<Argument> _arguments = new ArrayList<Argument>(); + + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String REF_PACKAGE = "refPackage"; + private static final String REF_CLASS = "refClass"; + private static final String UNIT = "unit"; + private static final String MIN = "min"; + private static final String MAX = "max"; + private static final String MAX_LENGTH = "maxlen"; + private static final String DESCRIPTION = "desc"; + private static final String DEFAULT = "default"; + private static final String DIRECTION = "dir"; + private static final String ARG_COUNT = "argCount"; + + + + public enum Direction + { + I, + O, + IO; + } + + public class Argument + { + private final LinkedHashMap<String,Object> _map = new LinkedHashMap<String,Object>(); + + public Argument(String name, QMFType type) + { + _map.put(NAME, name); + _map.put(TYPE, type.codeValue()); + } + + public void setRefPackage(String refPackage) + { + _map.put(REF_PACKAGE, refPackage); + } + + public void setRefClass(String refClass) + { + _map.put(REF_CLASS, refClass); + } + + public void setUnit(String unit) + { + _map.put(UNIT, unit); + } + + public void setMax(Number max) + { + _map.put(MAX, max); + } + + public void setMin(Number min) + { + _map.put(MIN, min); + } + + public void setMaxLength(int len) + { + _map.put(MAX_LENGTH, len); + } + + public void setDefault(Object dflt) + { + _map.put(DEFAULT, dflt); + } + + public void setDescription(String desc) + { + _map.put(DESCRIPTION, desc); + } + + public void setDirection(Direction direction) + { + _map.put(DIRECTION, direction.toString()); + } + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + } + + public String getName() + { + return (String) _map.get(NAME); + } + } + + public QMFMethod(String name, String description) + { + _map.put(NAME, name); + _map.put(ARG_COUNT, 0); + if(description != null) + { + _map.put(DESCRIPTION, description); + } + + } + + abstract public QMFMethodInvocation<T> parse(final BBDecoder decoder); + + protected void addArgument(Argument arg) + { + _arguments.add(arg); + _map.put(ARG_COUNT, _arguments.size()); + } + + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + for(Argument arg : _arguments) + { + arg.encode(encoder); + } + } + + public String getName() + { + return (String) _map.get(NAME); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java new file mode 100644 index 0000000000..5348c2783f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodInvocation.java @@ -0,0 +1,26 @@ +/* + * + * 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.qpid.qmf; + +public interface QMFMethodInvocation<T extends QMFObject> +{ + QMFMethodResponseCommand execute(T obj, QMFMethodRequestCommand cmd); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java new file mode 100644 index 0000000000..cf27e4b970 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java @@ -0,0 +1,88 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.AMQException; + +import java.util.UUID; +import java.util.ArrayList; + +public class QMFMethodRequestCommand extends QMFCommand +{ + private QMFMethodInvocation _methodInstance; + private QMFObject _object; + + public QMFMethodRequestCommand(final QMFCommandHeader header, final BBDecoder decoder, final QMFService qmfService) + { + super(header); + UUID objectId = decoder.readUuid(); + String packageName = decoder.readStr8(); + String className = decoder.readStr8(); + byte[] hash = decoder.readBin128(); + String methodName = decoder.readStr8(); + + QMFPackage qmfPackage = qmfService.getPackage(packageName); + QMFClass qmfClass = qmfPackage.getQMFClass(className); + _object = qmfService.getObjectById(qmfClass, objectId); + QMFMethod method = qmfClass.getMethod(methodName); + _methodInstance = method.parse(decoder); + + } + + public void process(final VirtualHost virtualHost, final ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String queueName = message.getMessageHeader().getReplyToRoutingKey(); + + QMFCommand[] commands = new QMFCommand[2]; + commands[0] = _methodInstance.execute(_object, this); + commands[1] = new QMFCommandCompletionCommand(this); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + for(QMFCommand cmd : commands) + { + QMFMessage responseMessage = new QMFMessage(queueName, cmd); + + + ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java new file mode 100644 index 0000000000..529b04ebdb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodResponseCommand.java @@ -0,0 +1,43 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFMethodResponseCommand extends QMFCommand +{ + public QMFMethodResponseCommand(final QMFMethodRequestCommand cmd) + { + super( new QMFCommandHeader(cmd.getHeader().getVersion(), + cmd.getHeader().getSeq(), + QMFOperation.METHOD_RESPONSE)); + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUint32(0); + encoder.writeStr16("OK"); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java new file mode 100644 index 0000000000..d126717fc8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java @@ -0,0 +1,76 @@ +/* + * + * 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.qpid.qmf; + +import java.util.UUID; + +public abstract class QMFObject<C extends QMFClass, D extends QMFObject.Delegate> +{ + private long _deleteTime; + + public interface Delegate + { + UUID getId(); + long getCreateTime(); + } + + + private D _delegate; + + protected QMFObject(D delegate) + { + _delegate = delegate; + } + + public D getDelegate() + { + return _delegate; + } + + abstract public C getQMFClass(); + + public final UUID getId() + { + return _delegate.getId(); + } + + public final long getCreateTime() + { + return _delegate.getCreateTime(); + } + + public final void setDeleteTime() + { + _deleteTime = System.currentTimeMillis(); + } + + public final long getDeleteTime() + { + return _deleteTime; + } + + + + abstract public QMFCommand asConfigInfoCmd(long sampleTime); + abstract public QMFCommand asInstrumentInfoCmd(long sampleTime); + abstract public QMFCommand asGetQueryResponseCmd(final QMFGetQueryCommand queryCommand, long sampleTime); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java new file mode 100644 index 0000000000..fefdecb8d7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObjectClass.java @@ -0,0 +1,44 @@ +/* + * + * 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.qpid.qmf; + +import java.util.List; + +public abstract class QMFObjectClass<T extends QMFObject, S extends QMFObject.Delegate> extends QMFClass +{ + public QMFObjectClass(String name, + byte[] schemaHash, + List<QMFProperty> properties, + List<QMFStatistic> statistics, List<QMFMethod> methods) + { + super(QMFClass.Type.OBJECT, name, schemaHash, properties, statistics, methods); + } + + public QMFObjectClass(String name, byte[] schemaHash) + { + super(QMFClass.Type.OBJECT, name, schemaHash); + } + + + public abstract T newInstance(S delegate); + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java new file mode 100644 index 0000000000..6736b5d460 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFOperation.java @@ -0,0 +1,67 @@ +/* + * + * 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.qpid.qmf; + +public enum QMFOperation +{ + + + BROKER_REQUEST('B'), + BROKER_RESPONSE('b'), // This message contains a broker response, sent from the broker in response to a broker request message. + COMMAND_COMPLETION('z'), // This message is sent to indicate the completion of a request. + CLASS_QUERY('Q'), // Class query messages are used by a management console to request a list of schema classes that are known by the management broker. + CLASS_INDICATION('q'), // Sent by the management broker, a class indication notifies the peer of the existence of a schema class. + SCHEMA_REQUEST('S'), // Schema request messages are used to request the full schema details for a class. + SCHEMA_RESPONSE('s'), // Schema response message contain a full description of the schema for a class. + HEARTBEAT_INDEICATION('h'), // This message is published once per publish-interval. It can be used by a client to positively determine which objects did not change during the interval (since updates are not published for objects with no changes). + CONFIG_INDICATION('c'), + INSTRUMENTATION_INDICATION('i'), + GET_QUERY_RESPONSE('g'), // This message contains a content record. Content records contain the values of all properties or statistics in an object. Such records are broadcast on a periodic interval if 1) a change has been made in the value of one of the elements, or 2) if a new management client has bound a queue to the management exchange. + GET_QUERY('G'), // Sent by a management console, a get query requests that the management broker provide content indications for all objects that match the query criteria. + METHOD_REQUEST('M'), // This message contains a method request. + METHOD_RESPONSE('m'), // This message contains a method result. + PACKAGE_QUERY('P'), // This message contains a schema package query request, requesting that the broker dump the list of known packages + PACKAGE_INDICATION('p'), // This message contains a schema package indication, identifying a package known by the broker + AGENT_ATTACH_REUQEST('A'), // This message is sent by a remote agent when it wishes to attach to a management broker + AGENT_ATTACH_RESPONSE('a'), // The management broker sends this response if an attaching remote agent is permitted to join + CONSOLE_ADDED_INDICATION('x'), // This message is sent to all remote agents by the management broker when a new console binds to the management exchange + EVENT('e') + ; + + + private final char _opcode; + + private static final QMFOperation[] OP_CODES = new QMFOperation[256]; + + + QMFOperation(char opcode) + { + _opcode = opcode; + } + + + public char getOpcode() + { + return _opcode; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java new file mode 100644 index 0000000000..681e64b799 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackage.java @@ -0,0 +1,67 @@ +/* + * + * 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.qpid.qmf; + +import java.util.Collection; +import java.util.Map; +import java.util.HashMap; + +public class QMFPackage +{ + private final String _name; + private final Map<String, QMFClass> _classes = new HashMap<String, QMFClass>(); + + public QMFPackage(String name) + { + _name = name; + } + + public QMFPackage(String name, Collection<QMFClass> classes) + { + this(name); + setClasses(classes); + } + + protected void setClasses(Collection<QMFClass> classes) + { + for(QMFClass qmfClass : classes) + { + qmfClass.setPackage(this); + _classes.put(qmfClass.getName(), qmfClass); + } + } + + public String getName() + { + return _name; + } + + public Collection<QMFClass> getClasses() + { + return _classes.values(); + } + + public QMFClass getQMFClass(String className) + { + return _classes.get(className); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java new file mode 100644 index 0000000000..7053b80655 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageIndicationCommand.java @@ -0,0 +1,46 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +public class QMFPackageIndicationCommand extends QMFCommand +{ + private String _supportedSchema; + + public QMFPackageIndicationCommand(QMFPackageQueryCommand qmfPackageQueryCommand, String supportedSchema) + { + super( new QMFCommandHeader(qmfPackageQueryCommand.getHeader().getVersion(), + qmfPackageQueryCommand.getHeader().getSeq(), + QMFOperation.PACKAGE_INDICATION)); + _supportedSchema = supportedSchema; + + } + + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeStr8(_supportedSchema); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java new file mode 100644 index 0000000000..6defd088de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java @@ -0,0 +1,86 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.AMQException; + +import java.util.ArrayList; +import java.util.Collection; + +public class QMFPackageQueryCommand extends QMFCommand +{ + public QMFPackageQueryCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + Collection<QMFPackage> supportedSchemas = service.getSupportedSchemas(); + + QMFCommand[] commands = new QMFCommand[ supportedSchemas.size() + 1 ]; + + int i = 0; + for(QMFPackage p : supportedSchemas) + { + commands[i++] = new QMFPackageIndicationCommand(this, p.getName()); + } + commands[ commands.length - 1 ] = new QMFCommandCompletionCommand(this); + + + for(QMFCommand cmd : commands) + { + + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java new file mode 100644 index 0000000000..5748722afe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFProperty.java @@ -0,0 +1,123 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.Encoder; + +import java.util.Map; +import java.util.HashMap; +import java.util.LinkedHashMap; + +public class QMFProperty +{ + private final Map<String, Object> _map = new LinkedHashMap<String, Object>(); + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String ACCESS = "access"; + private static final String INDEX = "index"; + private static final String OPTIONAL = "optional"; + private static final String REF_PACKAGE = "refPackage"; + private static final String REF_CLASS = "refClass"; + private static final String UNIT = "unit"; + private static final String MIN = "min"; + private static final String MAX = "max"; + private static final String MAX_LENGTH = "maxlen"; + private static final String DESCRIPTION = "desc"; + + + public static enum AccessCode + { + RC, + RW, + RO; + + public int codeValue() + { + return ordinal()+1; + } + } + + public QMFProperty(String name, QMFType type, AccessCode accessCode, boolean index, boolean optional) + { + _map.put(NAME, name); + _map.put(TYPE, type.codeValue()); + _map.put(ACCESS, accessCode.codeValue()); + _map.put(INDEX, index ? 1 : 0); + _map.put(OPTIONAL, optional ? 1 :0); + } + + + public void setQMFClass(QMFClass qmfClass) + { + /* _map.put(REF_CLASS, qmfClass.getName()); + _map.put(REF_PACKAGE, qmfClass.getPackage().getName());*/ + } + + public void setReferencedClass(String refClass) + { + _map.put(REF_CLASS, refClass); + } + + public void setReferencedPackage(String refPackage) + { + _map.put(REF_CLASS, refPackage); + } + + + public String getName() + { + return (String) _map.get(NAME); + } + + + public void setUnit(String unit) + { + _map.put(UNIT, unit); + } + + public void setMin(Number min) + { + _map.put(MIN, min); + } + + public void setMax(Number max) + { + _map.put(MAX, max); + } + + public void setMaxLength(int maxlen) + { + _map.put(MAX_LENGTH, maxlen); + } + + + public void setDescription(String description) + { + _map.put(DESCRIPTION, description); + } + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java new file mode 100644 index 0000000000..3141676f10 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java @@ -0,0 +1,88 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.AMQException; + +import java.util.Collection; +import java.util.ArrayList; + +public class QMFSchemaRequestCommand extends QMFCommand +{ + private final String _packageName; + private final String _className; + private final byte[] _hash; + + public QMFSchemaRequestCommand(QMFCommandHeader header, BBDecoder decoder) + { + super(header); + _packageName = decoder.readStr8(); + _className = decoder.readStr8(); + _hash = decoder.readBin128(); + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + QMFPackage qmfPackage = service.getPackage(_packageName); + QMFClass qmfClass = qmfPackage.getQMFClass( _className ); + + QMFCommand[] commands = new QMFCommand[2]; + commands[0] = new QMFSchemaResponseCommand(this, qmfClass); + commands[ 1 ] = new QMFCommandCompletionCommand(this); + + + + Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); + + for(QMFCommand cmd : commands) + { + QMFMessage responseMessage = new QMFMessage(routingKey, cmd); + + + ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + + for(BaseQueue q : queues) + { + try + { + q.enqueue(responseMessage); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java new file mode 100644 index 0000000000..fea2430130 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaResponseCommand.java @@ -0,0 +1,83 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; + +import java.util.Collection; + +public class QMFSchemaResponseCommand extends QMFCommand +{ + private final QMFClass _qmfClass; + + + public QMFSchemaResponseCommand(QMFSchemaRequestCommand qmfSchemaRequestCommand, QMFClass qmfClass) + { + super(new QMFCommandHeader(qmfSchemaRequestCommand.getHeader().getVersion(), + qmfSchemaRequestCommand.getHeader().getSeq(), + QMFOperation.SCHEMA_RESPONSE)); + _qmfClass = qmfClass; + } + + @Override + public void encode(BBEncoder encoder) + { + super.encode(encoder); + encoder.writeUint8(_qmfClass.getType().getValue()); + encoder.writeStr8(_qmfClass.getPackage().getName()); + encoder.writeStr8(_qmfClass.getName()); + encoder.writeBin128(_qmfClass.getSchemaHash()); + + Collection<QMFProperty> props = _qmfClass.getProperties(); + Collection<QMFStatistic> stats = _qmfClass.getStatistics(); + Collection<QMFMethod> methods = _qmfClass.getMethods(); + + encoder.writeUint16(props.size()); + if(_qmfClass.getType() == QMFClass.Type.OBJECT) + { + encoder.writeUint16(stats.size()); + encoder.writeUint16(methods.size()); + } + + for(QMFProperty prop : props) + { + prop.encode(encoder); + } + + if(_qmfClass.getType() == QMFClass.Type.OBJECT) + { + + for(QMFStatistic stat : stats) + { + stat.encode(encoder); + } + + for(QMFMethod method : methods) + { + method.encode(encoder); + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java new file mode 100644 index 0000000000..6a1c24b5a7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -0,0 +1,1583 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.qmf.schema.BrokerSchema; +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.registry.IApplicationRegistry; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public class QMFService implements ConfigStore.ConfigEventListener +{ + + + private IApplicationRegistry _applicationRegistry; + private ConfigStore _configStore; + + + private final Map<String, QMFPackage> _supportedSchemas = new HashMap<String, QMFPackage>(); + private static final Map<String, ConfigObjectType> _qmfClassMapping = new HashMap<String, ConfigObjectType>(); + + static + { + _qmfClassMapping.put("system", SystemConfigType.getInstance()); + _qmfClassMapping.put("broker", BrokerConfigType.getInstance()); + _qmfClassMapping.put("vhost", VirtualHostConfigType.getInstance()); + _qmfClassMapping.put("exchange", ExchangeConfigType.getInstance()); + _qmfClassMapping.put("queue", QueueConfigType.getInstance()); + _qmfClassMapping.put("binding", BindingConfigType.getInstance()); + _qmfClassMapping.put("connection", ConnectionConfigType.getInstance()); + _qmfClassMapping.put("session", SessionConfigType.getInstance()); + _qmfClassMapping.put("subscription", SubscriptionConfigType.getInstance()); + _qmfClassMapping.put("link", LinkConfigType.getInstance()); + _qmfClassMapping.put("bridge", BridgeConfigType.getInstance()); + } + + private final Map<ConfigObjectType, ConfigObjectAdapter> _adapterMap = + new HashMap<ConfigObjectType, ConfigObjectAdapter>(); + private final Map<ConfigObjectType,QMFClass> _classMap = + new HashMap<ConfigObjectType,QMFClass>(); + + + private final ConcurrentHashMap<QMFClass,ConcurrentHashMap<ConfiguredObject, QMFObject>> _managedObjects = + new ConcurrentHashMap<QMFClass,ConcurrentHashMap<ConfiguredObject, QMFObject>>(); + + private final ConcurrentHashMap<QMFClass,ConcurrentHashMap<UUID, QMFObject>> _managedObjectsById = + new ConcurrentHashMap<QMFClass,ConcurrentHashMap<UUID, QMFObject>>(); + + private static final BrokerSchema PACKAGE = BrokerSchema.getPackage(); + + public static interface Listener + { + public void objectCreated(QMFObject obj); + public void objectDeleted(QMFObject obj); + } + + private final CopyOnWriteArrayList<Listener> _listeners = new CopyOnWriteArrayList<Listener>(); + + abstract class ConfigObjectAdapter<Q extends QMFObject<S,D>, S extends QMFObjectClass<Q,D>, D extends QMFObject.Delegate, T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T,C>> + { + private final T _type; + private final S _qmfClass; + + + protected ConfigObjectAdapter(final T type, final S qmfClass) + { + _type = type; + _qmfClass = qmfClass; + _adapterMap.put(type,this); + _classMap.put(type,qmfClass); + } + + public T getType() + { + return _type; + } + + public S getQMFClass() + { + return _qmfClass; + } + + protected final Q newInstance(D delegate) + { + return _qmfClass.newInstance(delegate); + } + + public abstract Q createQMFObject(C configObject); + } + + private ConfigObjectAdapter<BrokerSchema.SystemObject, + BrokerSchema.SystemClass, + BrokerSchema.SystemDelegate, + SystemConfigType, + SystemConfig> _systemObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.SystemObject, + BrokerSchema.SystemClass, + BrokerSchema.SystemDelegate, + SystemConfigType, + SystemConfig>(SystemConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.SystemClass.class)) + { + + + public BrokerSchema.SystemObject createQMFObject( + final SystemConfig configObject) + { + return newInstance(new SystemDelegate(configObject)); + } + }; + + private ConfigObjectAdapter<BrokerSchema.BrokerObject, + BrokerSchema.BrokerClass, + BrokerSchema.BrokerDelegate, + BrokerConfigType, + BrokerConfig> _brokerObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.BrokerObject, + BrokerSchema.BrokerClass, + BrokerSchema.BrokerDelegate, + BrokerConfigType, + BrokerConfig>(BrokerConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.BrokerClass.class)) + { + + public BrokerSchema.BrokerObject createQMFObject( + final BrokerConfig configObject) + { + return newInstance(new BrokerDelegate(configObject)); + } + }; + + private ConfigObjectAdapter<BrokerSchema.VhostObject, + BrokerSchema.VhostClass, + BrokerSchema.VhostDelegate, + VirtualHostConfigType, + VirtualHostConfig> _vhostObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.VhostObject, + BrokerSchema.VhostClass, + BrokerSchema.VhostDelegate, + VirtualHostConfigType, + VirtualHostConfig>(VirtualHostConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.VhostClass.class)) + { + + public BrokerSchema.VhostObject createQMFObject( + final VirtualHostConfig configObject) + { + return newInstance(new VhostDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.ExchangeObject, + BrokerSchema.ExchangeClass, + BrokerSchema.ExchangeDelegate, + ExchangeConfigType, + ExchangeConfig> _exchangeObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.ExchangeObject, + BrokerSchema.ExchangeClass, + BrokerSchema.ExchangeDelegate, + ExchangeConfigType, + ExchangeConfig>(ExchangeConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.ExchangeClass.class)) + { + + public BrokerSchema.ExchangeObject createQMFObject( + final ExchangeConfig configObject) + { + return newInstance(new ExchangeDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.QueueObject, + BrokerSchema.QueueClass, + BrokerSchema.QueueDelegate, + QueueConfigType, + QueueConfig> _queueObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.QueueObject, + BrokerSchema.QueueClass, + BrokerSchema.QueueDelegate, + QueueConfigType, + QueueConfig>(QueueConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.QueueClass.class)) + { + + public BrokerSchema.QueueObject createQMFObject( + final QueueConfig configObject) + { + return newInstance(new QueueDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.BindingObject, + BrokerSchema.BindingClass, + BrokerSchema.BindingDelegate, + BindingConfigType, + BindingConfig> _bindingObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.BindingObject, + BrokerSchema.BindingClass, + BrokerSchema.BindingDelegate, + BindingConfigType, + BindingConfig>(BindingConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.BindingClass.class)) + { + + public BrokerSchema.BindingObject createQMFObject( + final BindingConfig configObject) + { + return newInstance(new BindingDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.ConnectionObject, + BrokerSchema.ConnectionClass, + BrokerSchema.ConnectionDelegate, + ConnectionConfigType, + ConnectionConfig> _connectionObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.ConnectionObject, + BrokerSchema.ConnectionClass, + BrokerSchema.ConnectionDelegate, + ConnectionConfigType, + ConnectionConfig>(ConnectionConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.ConnectionClass.class)) + { + + public BrokerSchema.ConnectionObject createQMFObject( + final ConnectionConfig configObject) + { + return newInstance(new ConnectionDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.SessionObject, + BrokerSchema.SessionClass, + BrokerSchema.SessionDelegate, + SessionConfigType, + SessionConfig> _sessionObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.SessionObject, + BrokerSchema.SessionClass, + BrokerSchema.SessionDelegate, + SessionConfigType, + SessionConfig>(SessionConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.SessionClass.class)) + { + + public BrokerSchema.SessionObject createQMFObject( + final SessionConfig configObject) + { + return newInstance(new SessionDelegate(configObject)); + } + }; + + private ConfigObjectAdapter<BrokerSchema.SubscriptionObject, + BrokerSchema.SubscriptionClass, + BrokerSchema.SubscriptionDelegate, + SubscriptionConfigType, + SubscriptionConfig> _subscriptionObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.SubscriptionObject, + BrokerSchema.SubscriptionClass, + BrokerSchema.SubscriptionDelegate, + SubscriptionConfigType, + SubscriptionConfig>(SubscriptionConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.SubscriptionClass.class)) + { + + public BrokerSchema.SubscriptionObject createQMFObject( + final SubscriptionConfig configObject) + { + return newInstance(new SubscriptionDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.LinkObject, + BrokerSchema.LinkClass, + BrokerSchema.LinkDelegate, + LinkConfigType, + LinkConfig> _linkObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.LinkObject, + BrokerSchema.LinkClass, + BrokerSchema.LinkDelegate, + LinkConfigType, + LinkConfig>(LinkConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.LinkClass.class)) + { + + public BrokerSchema.LinkObject createQMFObject( + final LinkConfig configObject) + { + return newInstance(new LinkDelegate(configObject)); + } + }; + + + private ConfigObjectAdapter<BrokerSchema.BridgeObject, + BrokerSchema.BridgeClass, + BrokerSchema.BridgeDelegate, + BridgeConfigType, + BridgeConfig> _bridgeObjectAdapter = + new ConfigObjectAdapter<BrokerSchema.BridgeObject, + BrokerSchema.BridgeClass, + BrokerSchema.BridgeDelegate, + BridgeConfigType, + BridgeConfig>(BridgeConfigType.getInstance(), + PACKAGE.getQMFClassInstance(BrokerSchema.BridgeClass.class)) + { + + public BrokerSchema.BridgeObject createQMFObject( + final BridgeConfig configObject) + { + return newInstance(new BridgeDelegate(configObject)); + } + }; + + + + public QMFService(ConfigStore configStore, IApplicationRegistry applicationRegistry) + { + _configStore = configStore; + _applicationRegistry = applicationRegistry; + registerSchema(PACKAGE); + + for(ConfigObjectType v : _qmfClassMapping.values()) + { + configStore.addConfigEventListener(v, this); + } + init(); + } + + public void close() + { + _managedObjects.clear(); + _managedObjectsById.clear(); + _classMap.clear(); + _adapterMap.clear(); + _supportedSchemas.clear(); + } + + + public void registerSchema(QMFPackage qmfPackage) + { + _supportedSchemas.put(qmfPackage.getName(), qmfPackage); + } + + + public Collection<QMFPackage> getSupportedSchemas() + { + return _supportedSchemas.values(); + } + + public QMFPackage getPackage(String aPackage) + { + return _supportedSchemas.get(aPackage); + } + + public void onEvent(final ConfiguredObject object, final ConfigStore.Event evt) + { + + switch (evt) + { + case CREATED: + manageObject(object); + break; + + case DELETED: + unmanageObject(object); + break; + } + } + + public QMFObject getObjectById(QMFClass qmfclass, UUID id) + { + ConcurrentHashMap<UUID, QMFObject> map = _managedObjectsById.get(qmfclass); + if(map != null) + { + return map.get(id); + } + else + { + return null; + } + } + + private void unmanageObject(final ConfiguredObject object) + { + final QMFClass qmfClass = _classMap.get(object.getConfigType()); + + ConcurrentHashMap<ConfiguredObject, QMFObject> classObjects = _managedObjects.get(qmfClass); + if(classObjects != null) + { + QMFObject qmfObject = classObjects.remove(object); + if(qmfObject != null) + { + _managedObjectsById.get(qmfClass).remove(object.getId()); + objectRemoved(qmfObject); + } + } + } + + private void manageObject(final ConfiguredObject object) + { + ConfigObjectAdapter adapter = _adapterMap.get(object.getConfigType()); + QMFObject qmfObject = adapter.createQMFObject(object); + final QMFClass qmfClass = qmfObject.getQMFClass(); + ConcurrentHashMap<ConfiguredObject, QMFObject> classObjects = _managedObjects.get(qmfClass); + + if(classObjects == null) + { + classObjects = new ConcurrentHashMap<ConfiguredObject, QMFObject>(); + if(_managedObjects.putIfAbsent(qmfClass, classObjects) != null) + { + classObjects = _managedObjects.get(qmfClass); + } + } + + ConcurrentHashMap<UUID, QMFObject> classObjectsById = _managedObjectsById.get(qmfClass); + if(classObjectsById == null) + { + classObjectsById = new ConcurrentHashMap<UUID, QMFObject>(); + if(_managedObjectsById.putIfAbsent(qmfClass, classObjectsById) != null) + { + classObjectsById = _managedObjectsById.get(qmfClass); + } + } + + classObjectsById.put(object.getId(),qmfObject); + + if(classObjects.putIfAbsent(object, qmfObject) == null); + { + objectAdded(qmfObject); + } + } + + private void objectRemoved(final QMFObject qmfObject) + { + qmfObject.setDeleteTime(); + for(Listener l : _listeners) + { + l.objectDeleted(qmfObject); + } + } + + private void objectAdded(final QMFObject qmfObject) + { + for(Listener l : _listeners) + { + l.objectCreated(qmfObject); + } + } + + public void addListener(Listener l) + { + _listeners.add(l); + } + + public void removeListener(Listener l) + { + _listeners.remove(l); + } + + + private void init() + { + for(QMFClass qmfClass : PACKAGE.getClasses()) + { + ConfigObjectType configType = getConfigType(qmfClass); + if(configType != null) + { + Collection<ConfiguredObject> objects = _configStore.getConfiguredObjects(configType); + for(ConfiguredObject object : objects) + { + manageObject(object); + } + } + } + } + + public Collection<QMFObject> getObjects(QMFClass qmfClass) + { + ConcurrentHashMap<ConfiguredObject, QMFObject> classObjects = _managedObjects.get(qmfClass); + if(classObjects != null) + { + return classObjects.values(); + } + else + { + return Collections.EMPTY_SET; + } + } + + private QMFObject adapt(final ConfiguredObject object) + { + if(object == null) + { + return null; + } + + QMFClass qmfClass = _classMap.get(object.getConfigType()); + ConcurrentHashMap<ConfiguredObject, QMFObject> classObjects = _managedObjects.get(qmfClass); + if(classObjects != null) + { + QMFObject qmfObject = classObjects.get(object); + if(qmfObject != null) + { + return qmfObject; + } + } + + return _adapterMap.get(object.getConfigType()).createQMFObject(object); + } + + private ConfigObjectType getConfigType(final QMFClass qmfClass) + { + return _qmfClassMapping.get(qmfClass.getName()); + } + + private static class SystemDelegate implements BrokerSchema.SystemDelegate + { + private final SystemConfig _obj; + + public SystemDelegate(final SystemConfig obj) + { + _obj = obj; + } + + public UUID getSystemId() + { + return _obj.getId(); + } + + public String getOsName() + { + return _obj.getOperatingSystemName(); + } + + public String getNodeName() + { + return _obj.getNodeName(); + } + + public String getRelease() + { + return _obj.getOSRelease(); + } + + public String getVersion() + { + return _obj.getOSVersion(); + } + + public String getMachine() + { + return _obj.getOSArchitecture(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class BrokerDelegate implements BrokerSchema.BrokerDelegate + { + private final BrokerConfig _obj; + + public BrokerDelegate(final BrokerConfig obj) + { + _obj = obj; + } + + public BrokerSchema.SystemObject getSystemRef() + { + return (BrokerSchema.SystemObject) adapt(_obj.getSystem()); + } + + public Integer getPort() + { + return _obj.getPort(); + } + + public Integer getWorkerThreads() + { + return _obj.getWorkerThreads(); + } + + public Integer getMaxConns() + { + return _obj.getMaxConnections(); + } + + public Integer getConnBacklog() + { + return _obj.getConnectionBacklogLimit(); + } + + public Long getStagingThreshold() + { + return _obj.getStagingThreshold(); + } + + public Integer getMgmtPubInterval() + { + return _obj.getManagementPublishInterval(); + } + + public String getVersion() + { + return _obj.getVersion(); + } + + public String getDataDir() + { + return _obj.getDataDirectory(); + } + + public Long getUptime() + { + return (System.currentTimeMillis() - _obj.getCreateTime()) * 1000000L; + } + + public BrokerSchema.BrokerClass.EchoMethodResponseCommand echo(final BrokerSchema.BrokerClass.EchoMethodResponseCommandFactory factory, + final Long sequence, + final String body) + { + return factory.createResponseCommand(sequence, body); + } + + public BrokerSchema.BrokerClass.ConnectMethodResponseCommand connect(final BrokerSchema.BrokerClass.ConnectMethodResponseCommandFactory factory, + final String host, + final Long port, + final Boolean durable, + final String authMechanism, + final String username, + final String password, + final String transport) + { + _obj.createBrokerConnection(transport, host, port.intValue(), durable, authMechanism, username, password); + + return factory.createResponseCommand(); + } + + public BrokerSchema.BrokerClass.QueueMoveMessagesMethodResponseCommand queueMoveMessages(final BrokerSchema.BrokerClass.QueueMoveMessagesMethodResponseCommandFactory factory, + final String srcQueue, + final String destQueue, + final Long qty) + { + // todo + throw new UnsupportedOperationException(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class VhostDelegate implements BrokerSchema.VhostDelegate + { + private final VirtualHostConfig _obj; + + public VhostDelegate(final VirtualHostConfig obj) + { + _obj = obj; + } + + public BrokerSchema.BrokerObject getBrokerRef() + { + return (BrokerSchema.BrokerObject) adapt(_obj.getBroker()); + } + + public String getName() + { + return _obj.getName(); + } + + public String getFederationTag() + { + return _obj.getFederationTag(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class ExchangeDelegate implements BrokerSchema.ExchangeDelegate + { + private final ExchangeConfig _obj; + + public ExchangeDelegate(final ExchangeConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getName() + { + return _obj.getName(); + } + + public String getType() + { + return _obj.getType().getName().toString(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public Boolean getAutoDelete() + { + return _obj.isAutoDelete(); + } + + public BrokerSchema.ExchangeObject getAltExchange() + { + if(_obj.getAlternateExchange() != null) + { + return (BrokerSchema.ExchangeObject) adapt(_obj.getAlternateExchange()); + } + else + { + return null; + } + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public Long getProducerCount() + { + // TODO + return 0l; + } + + public Long getProducerCountHigh() + { + // TODO + return 0l; + } + + public Long getProducerCountLow() + { + // TODO + return 0l; + } + + public Long getBindingCount() + { + return _obj.getBindingCount(); + } + + public Long getBindingCountHigh() + { + return _obj.getBindingCountHigh(); + } + + public Long getBindingCountLow() + { + // TODO + return 0l; + } + + public Long getMsgReceives() + { + return _obj.getMsgReceives(); + } + + public Long getMsgDrops() + { + return getMsgReceives() - getMsgRoutes(); + } + + public Long getMsgRoutes() + { + return _obj.getMsgRoutes(); + } + + public Long getByteReceives() + { + return _obj.getByteReceives(); + } + + public Long getByteDrops() + { + return getByteReceives() - getByteRoutes(); + } + + public Long getByteRoutes() + { + return _obj.getByteRoutes(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class QueueDelegate implements BrokerSchema.QueueDelegate + { + private final QueueConfig _obj; + + public QueueDelegate(final QueueConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getName() + { + return _obj.getName(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public Boolean getAutoDelete() + { + return _obj.isAutoDelete(); + } + + public Boolean getExclusive() + { + return _obj.isExclusive(); + } + + public BrokerSchema.ExchangeObject getAltExchange() + { + if(_obj.getAlternateExchange() != null) + { + return (BrokerSchema.ExchangeObject) adapt(_obj.getAlternateExchange()); + } + else + { + return null; + } + } + + public Long getMsgTotalEnqueues() + { + return _obj.getReceivedMessageCount(); + } + + public Long getMsgTotalDequeues() + { + return _obj.getMessageDequeueCount(); + } + + public Long getMsgTxnEnqueues() + { + // TODO + return 0l; + } + + public Long getMsgTxnDequeues() + { + // TODO + return 0l; + } + + public Long getMsgPersistEnqueues() + { + return _obj.getPersistentMsgEnqueues(); + } + + public Long getMsgPersistDequeues() + { + return _obj.getPersistentMsgDequeues(); + } + + public Long getMsgDepth() + { + return (long) _obj.getMessageCount(); + } + + public Long getByteDepth() + { + return _obj.getQueueDepth(); + } + + public Long getByteTotalEnqueues() + { + return _obj.getTotalEnqueueSize(); + } + + public Long getByteTotalDequeues() + { + return _obj.getTotalDequeueSize(); + } + + public Long getByteTxnEnqueues() + { + // TODO + return 0l; + } + + public Long getByteTxnDequeues() + { + // TODO + return 0l; + } + + public Long getBytePersistEnqueues() + { + return _obj.getPersistentByteEnqueues(); + } + + public Long getBytePersistDequeues() + { + return _obj.getPersistentByteDequeues(); + } + + public Long getConsumerCount() + { + return (long) _obj.getConsumerCount(); + } + + public Long getConsumerCountHigh() + { + // TODO + return 0l; + } + + public Long getConsumerCountLow() + { + // TODO + return 0l; + } + + public Long getBindingCount() + { + return (long) _obj.getBindingCount(); + } + + public Long getBindingCountHigh() + { + return (long) _obj.getBindingCountHigh(); + } + + public Long getBindingCountLow() + { + // TODO + return 0l; + } + + public Long getUnackedMessages() + { + // TODO + return 0l; + } + + public Long getUnackedMessagesHigh() + { + // TODO + return 0l; + } + + public Long getUnackedMessagesLow() + { + // TODO + return 0l; + } + + public Long getMessageLatencySamples() + { + // TODO + return 0l; + } + + public Long getMessageLatencyMin() + { + // TODO + return 0l; + } + + public Long getMessageLatencyMax() + { + // TODO + return 0l; + } + + public Long getMessageLatencyAverage() + { + // TODO + return 0l; + } + + public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory, + final Long request) + { + _obj.purge(request); + return factory.createResponseCommand(); + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class BindingDelegate implements BrokerSchema.BindingDelegate + { + private final BindingConfig _obj; + + public BindingDelegate(final BindingConfig obj) + { + _obj = obj; + } + + public BrokerSchema.ExchangeObject getExchangeRef() + { + return (BrokerSchema.ExchangeObject) adapt(_obj.getExchange()); + } + + public BrokerSchema.QueueObject getQueueRef() + { + return (BrokerSchema.QueueObject) adapt(_obj.getQueue()); + } + + public String getBindingKey() + { + return _obj.getBindingKey(); + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public String getOrigin() + { + return _obj.getOrigin(); + } + + public Long getMsgMatched() + { + // TODO + return _obj.getMatches(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class ConnectionDelegate implements BrokerSchema.ConnectionDelegate + { + private final ConnectionConfig _obj; + + public ConnectionDelegate(final ConnectionConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getAddress() + { + return _obj.getAddress(); + } + + public Boolean getIncoming() + { + return _obj.isIncoming(); + } + + public Boolean getSystemConnection() + { + return _obj.isSystemConnection(); + } + + public Boolean getFederationLink() + { + return _obj.isFederationLink(); + } + + public String getAuthIdentity() + { + return _obj.getAuthId(); + } + + public String getRemoteProcessName() + { + return _obj.getRemoteProcessName(); + } + + public Long getRemotePid() + { + Integer remotePID = _obj.getRemotePID(); + return remotePID == null ? null : (long) remotePID; + } + + public Long getRemoteParentPid() + { + Integer remotePPID = _obj.getRemoteParentPID(); + return remotePPID == null ? null : (long) remotePPID; + + } + + public Boolean getClosing() + { + return false; + } + + public Long getFramesFromClient() + { + // TODO + return 0l; + } + + public Long getFramesToClient() + { + // TODO + return 0l; + } + + public Long getBytesFromClient() + { + // TODO + return 0l; + } + + public Long getBytesToClient() + { + // TODO + return 0l; + } + + public BrokerSchema.ConnectionClass.CloseMethodResponseCommand close(final BrokerSchema.ConnectionClass.CloseMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + // TODO + return 0; + } + } + + private class SessionDelegate implements BrokerSchema.SessionDelegate + { + private final SessionConfig _obj; + + public SessionDelegate(final SessionConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getName() + { + return _obj.getSessionName(); + } + + public Integer getChannelId() + { + return _obj.getChannel(); + } + + public BrokerSchema.ConnectionObject getConnectionRef() + { + return (BrokerSchema.ConnectionObject) adapt(_obj.getConnectionConfig()); + } + + public Long getDetachedLifespan() + { + return _obj.getDetachedLifespan(); + } + + public Boolean getAttached() + { + return _obj.isAttached(); + } + + public Long getExpireTime() + { + return _obj.getExpiryTime(); + } + + public Long getMaxClientRate() + { + return _obj.getMaxClientRate(); + } + + public Long getFramesOutstanding() + { + // TODO + return 0l; + } + + public Long getTxnStarts() + { + // TODO + return 0l; + } + + public Long getTxnCommits() + { + // TODO + return 0l; + } + + public Long getTxnRejects() + { + // TODO + return 0l; + } + + public Long getTxnCount() + { + // TODO + return 0l; + } + + public Long getClientCredit() + { + // TODO + return 0l; + } + + public BrokerSchema.SessionClass.SolicitAckMethodResponseCommand solicitAck(final BrokerSchema.SessionClass.SolicitAckMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public BrokerSchema.SessionClass.DetachMethodResponseCommand detach(final BrokerSchema.SessionClass.DetachMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public BrokerSchema.SessionClass.ResetLifespanMethodResponseCommand resetLifespan(final BrokerSchema.SessionClass.ResetLifespanMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public BrokerSchema.SessionClass.CloseMethodResponseCommand close(final BrokerSchema.SessionClass.CloseMethodResponseCommandFactory factory) + { + //todo + throw new UnsupportedOperationException(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + // TODO + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + } + + private class SubscriptionDelegate implements BrokerSchema.SubscriptionDelegate + { + private final SubscriptionConfig _obj; + + private SubscriptionDelegate(final SubscriptionConfig obj) + { + _obj = obj; + } + + + public BrokerSchema.SessionObject getSessionRef() + { + return (BrokerSchema.SessionObject) adapt(_obj.getSessionConfig()); + } + + public BrokerSchema.QueueObject getQueueRef() + { + return (BrokerSchema.QueueObject) adapt(_obj.getQueue()); + } + + public String getName() + { + return _obj.getName(); + } + + public Boolean getBrowsing() + { + return _obj.isBrowsing(); + } + + public Boolean getAcknowledged() + { + return _obj.isExplicitAcknowledge(); + } + + public Boolean getExclusive() + { + return _obj.isExclusive(); + } + + public String getCreditMode() + { + return _obj.getCreditMode(); + } + + public Map getArguments() + { + return _obj.getArguments(); + } + + public Long getDelivered() + { + // TODO + return 0l; + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + // TODO + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + } + + private class BridgeDelegate implements BrokerSchema.BridgeDelegate + { + private final BridgeConfig _obj; + + private BridgeDelegate(final BridgeConfig obj) + { + _obj = obj; + } + + public BrokerSchema.LinkObject getLinkRef() + { + return (BrokerSchema.LinkObject) adapt(_obj.getLink()); + } + + public Integer getChannelId() + { + return _obj.getChannelId(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public String getSrc() + { + return _obj.getSource(); + } + + public String getDest() + { + return _obj.getDestination(); + } + + public String getKey() + { + return _obj.getKey(); + } + + public Boolean getSrcIsQueue() + { + return _obj.isQueueBridge(); + } + + public Boolean getSrcIsLocal() + { + return _obj.isLocalSource(); + } + + public String getTag() + { + return _obj.getTag(); + } + + public String getExcludes() + { + return _obj.getExcludes(); + } + + public Boolean getDynamic() + { + return _obj.isDynamic(); + } + + public Integer getSync() + { + return _obj.getAckBatching(); + } + + public BrokerSchema.BridgeClass.CloseMethodResponseCommand close(final BrokerSchema.BridgeClass.CloseMethodResponseCommandFactory factory) + { + return null; + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + + private class LinkDelegate implements BrokerSchema.LinkDelegate + { + private final LinkConfig _obj; + + private LinkDelegate(final LinkConfig obj) + { + _obj = obj; + } + + public BrokerSchema.VhostObject getVhostRef() + { + return (BrokerSchema.VhostObject) adapt(_obj.getVirtualHost()); + } + + public String getHost() + { + return _obj.getHost(); + } + + public Integer getPort() + { + return _obj.getPort(); + } + + public String getTransport() + { + return _obj.getTransport(); + } + + public Boolean getDurable() + { + return _obj.isDurable(); + } + + public String getState() + { + // TODO + return ""; + } + + public String getLastError() + { + // TODO + return ""; + } + + public BrokerSchema.LinkClass.CloseMethodResponseCommand close(final BrokerSchema.LinkClass.CloseMethodResponseCommandFactory factory) + { + _obj.close(); + return factory.createResponseCommand(); + } + + public BrokerSchema.LinkClass.BridgeMethodResponseCommand bridge(final BrokerSchema.LinkClass.BridgeMethodResponseCommandFactory factory, + final Boolean durable, + final String src, + final String dest, + final String key, + final String tag, + final String excludes, + final Boolean srcIsQueue, + final Boolean srcIsLocal, + final Boolean dynamic, + final Integer sync) + { + _obj.createBridge(durable, dynamic, srcIsQueue, srcIsLocal, src, dest, key, tag, excludes); + return factory.createResponseCommand(); + } + + public UUID getId() + { + return _obj.getId(); + } + + public long getCreateTime() + { + return _obj.getCreateTime(); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java new file mode 100644 index 0000000000..89d650e03b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFStatistic.java @@ -0,0 +1,61 @@ +/* + * + * 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.qpid.qmf; + +import org.apache.qpid.transport.codec.Encoder; + +import java.util.LinkedHashMap; + +public class QMFStatistic +{ + private final LinkedHashMap<String,Object> _map = new LinkedHashMap<String,Object>(); + private static final String NAME = "name"; + private static final String TYPE = "type"; + private static final String UNIT = "unit"; + private static final String DESCRIPTION = "desc"; + + + public QMFStatistic(String name, QMFType type, String unit, String description) + { + _map.put(NAME, name); + _map.put(TYPE, type.codeValue()); + if(unit != null) + { + _map.put(UNIT, unit); + } + if(description != null) + { + _map.put(DESCRIPTION, description); + } + + } + + public void encode(Encoder encoder) + { + encoder.writeMap(_map); + } + + public String getName() + { + return (String) _map.get(NAME); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java new file mode 100644 index 0000000000..0e01c27db5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFType.java @@ -0,0 +1,53 @@ +/* + * + * 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.qpid.qmf; + +public enum QMFType +{ + + UINT8, + UINT16, + UINT32, + UINT64, + UNKNOWN, + STR8, + STR16, + ABSTIME, + DELTATIME, + OBJECTREFERENCE, + BOOLEAN, + FLOAT, + DOUBLE, + UUID, + MAP, + INT8, + INT16, + INT32, + INT64, + OBJECT, + LIST, + ARRAY; + + public int codeValue() + { + return ordinal()+1; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 333c1b9cac..1b03ee2334 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,45 +20,72 @@ */ package org.apache.qpid.server; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SessionConfigType; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.subscription.ClientDeliveryMethod; -import org.apache.qpid.server.subscription.RecordDeliveryMethod; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoredMessage; -import org.apache.qpid.server.txn.*; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.messages.ChannelMessages; -import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.logging.actors.AMQPChannelActor; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ChannelMessages; +import org.apache.qpid.server.logging.subjects.ChannelLogSubject; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.protocol.AMQProtocolEngine; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.subscription.ClientDeliveryMethod; +import org.apache.qpid.server.subscription.RecordDeliveryMethod; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; -public class AMQChannel +public class AMQChannel implements SessionConfig { public static final int DEFAULT_PREFETCH = 5000; @@ -123,6 +150,7 @@ public class AMQChannel private List<QueueEntry> _resendList = new ArrayList<QueueEntry>(); private static final AMQShortString IMMEDIATE_DELIVERY_REPLY_TEXT = new AMQShortString("Immediate delivery is not possible."); + private final UUID _id; public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -132,15 +160,22 @@ public class AMQChannel _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); _logSubject = new ChannelLogSubject(this); - + _id = getConfigStore().createId(); _actor.message(ChannelMessages.CHN_CREATE()); + getConfigStore().addConfiguredObject(this); + _messageStore = messageStore; // by default the session is non-transactional _transaction = new AutoCommitTransaction(_messageStore); } + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { @@ -220,7 +255,7 @@ public class AMQChannel try { - final ArrayList<AMQQueue> destinationQueues = _currentMessage.getDestinationQueues(); + final ArrayList<? extends BaseQueue> destinationQueues = _currentMessage.getDestinationQueues(); if(!checkMessageUserId(_currentMessage.getContentHeader())) { @@ -411,6 +446,8 @@ public class AMQChannel _logger.error("Caught AMQException whilst attempting to reque:" + e); } + getConfigStore().removeConfiguredObject(this); + } private void setClosing(boolean closing) @@ -970,10 +1007,10 @@ public class AMQChannel private class MessageDeliveryAction implements ServerTransaction.Action { private IncomingMessage _incommingMessage; - private ArrayList<AMQQueue> _destinationQueues; + private ArrayList<? extends BaseQueue> _destinationQueues; public MessageDeliveryAction(IncomingMessage currentMessage, - ArrayList<AMQQueue> destinationQueues) + ArrayList<? extends BaseQueue> destinationQueues) { _incommingMessage = currentMessage; _destinationQueues = destinationQueues; @@ -988,53 +1025,24 @@ public class AMQChannel final AMQMessage amqMessage = createAMQMessage(_incommingMessage); MessageReference ref = amqMessage.newReference(); - for(AMQQueue queue : _destinationQueues) + for(final BaseQueue queue : _destinationQueues) { + BaseQueue.PostEnqueueAction action; - QueueEntry entry = queue.enqueue(amqMessage); - queue.checkCapacity(AMQChannel.this); - - - if(immediate && !entry.getDeliveredToConsumer() && entry.acquire()) + if(immediate) { + action = new ImmediateAction(queue); + } + else + { + action = null; + } + queue.enqueue(amqMessage, action); - ServerTransaction txn = new LocalTransaction(_messageStore); - Collection<QueueEntry> entries = new ArrayList<QueueEntry>(1); - entries.add(entry); - final AMQMessage message = (AMQMessage) entry.getMessage(); - txn.dequeue(queue, entry.getMessage(), - new MessageAcknowledgeAction(entries) - { - @Override - public void postCommit() - { - try - { - final - ProtocolOutputConverter outputConverter = - _session.getProtocolOutputConverter(); - - outputConverter.writeReturn(message.getMessagePublishInfo(), - message.getContentHeaderBody(), - message, - _channelId, - AMQConstant.NO_CONSUMERS.getCode(), - IMMEDIATE_DELIVERY_REPLY_TEXT); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } - super.postCommit(); - } - } - ); - txn.commit(); - - - - + if(queue instanceof AMQQueue) + { + ((AMQQueue)queue).checkCapacity(AMQChannel.this); } } @@ -1057,6 +1065,60 @@ public class AMQChannel // Maybe keep track of entries that were created and then delete them here in case of failure // to in memory enqueue } + + private class ImmediateAction implements BaseQueue.PostEnqueueAction + { + private final BaseQueue _queue; + + public ImmediateAction(BaseQueue queue) + { + _queue = queue; + } + + public void onEnqueue(QueueEntry entry) + { + if (!entry.getDeliveredToConsumer() && entry.acquire()) + { + + + ServerTransaction txn = new LocalTransaction(_messageStore); + Collection<QueueEntry> entries = new ArrayList<QueueEntry>(1); + entries.add(entry); + final AMQMessage message = (AMQMessage) entry.getMessage(); + txn.dequeue(_queue, entry.getMessage(), + new MessageAcknowledgeAction(entries) + { + @Override + public void postCommit() + { + try + { + final + ProtocolOutputConverter outputConverter = + _session.getProtocolOutputConverter(); + + outputConverter.writeReturn(message.getMessagePublishInfo(), + message.getContentHeaderBody(), + message, + _channelId, + AMQConstant.NO_CONSUMERS.getCode(), + IMMEDIATE_DELIVERY_REPLY_TEXT); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + super.postCommit(); + } + } + ); + txn.commit(); + + + } + + } + } } private class MessageAcknowledgeAction implements ServerTransaction.Action @@ -1163,7 +1225,7 @@ public class AMQChannel if(_blocking.compareAndSet(false,true)) { - _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getName().toString())); + _actor.message(_logSubject, ChannelMessages.CHN_FLOW_ENFORCED(queue.getNameShortString().toString())); flow(false); } } @@ -1188,9 +1250,70 @@ public class AMQChannel AMQMethodBody responseBody = methodRegistry.createChannelFlowBody(flow); _session.writeFrame(responseBody.generateFrame(_channelId)); } - + public boolean getBlocking() { return _blocking.get(); } + + public VirtualHost getVirtualHost() + { + return getProtocolSession().getVirtualHost(); + } + + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public SessionConfigType getConfigType() + { + return SessionConfigType.getInstance(); + } + + public int getChannel() + { + return getChannelId(); + } + + public boolean isAttached() + { + return true; + } + + public long getDetachedLifespan() + { + return 0; + } + + public ConnectionConfig getConnectionConfig() + { + return (AMQProtocolEngine)getProtocolSession(); + } + + public Long getExpiryTime() + { + return null; + } + + public Long getMaxClientRate() + { + return null; + } + + public boolean isDurable() + { + return false; + } + + public UUID getId() + { + return _id; + } + + public String getSessionName() + { + return getConnectionConfig().getAddress() + "/" + getChannelId(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java new file mode 100644 index 0000000000..0b689c16a7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java @@ -0,0 +1,117 @@ +/* + * + * 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.qpid.server.binding; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; + +public class Binding +{ + private final String _bindingKey; + private final AMQQueue _queue; + private final Exchange _exchange; + private final Map<String, Object> _arguments; + private final UUID _id; + private final AtomicLong _matches = new AtomicLong(); + + Binding(UUID id, final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> arguments) + { + _id = id; + _bindingKey = bindingKey; + _queue = queue; + _exchange = exchange; + _arguments = arguments == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(arguments); + } + + public UUID getId() + { + return _id; + } + + public String getBindingKey() + { + return _bindingKey; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public Exchange getExchange() + { + return _exchange; + } + + public Map<String, Object> getArguments() + { + return _arguments; + } + + public void incrementMatches() + { + _matches.incrementAndGet(); + } + + public long getMatches() + { + return _matches.get(); + } + + boolean isDurable() + { + return _queue.isDurable() && _exchange.isDurable(); + } + + @Override + public boolean equals(final Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Binding binding = (Binding) o; + + if (!_bindingKey.equals(binding._bindingKey)) return false; + if (!_exchange.equals(binding._exchange)) return false; + if (!_queue.equals(binding._queue)) return false; + + return true; + } + + @Override + public int hashCode() + { + int result = _bindingKey.hashCode(); + result = 31 * result + _queue.hashCode(); + result = 31 * result + _exchange.hashCode(); + return result; + } + + + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java new file mode 100644 index 0000000000..e11af5d553 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -0,0 +1,290 @@ +/* + * + * 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.qpid.server.binding; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.configuration.BindingConfig; +import org.apache.qpid.server.configuration.BindingConfigType; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BindingMessages; +import org.apache.qpid.server.logging.subjects.BindingLogSubject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class BindingFactory +{ + + private final VirtualHost _virtualHost; + private final DurableConfigurationStore.Source _configSource; + private final Exchange _defaultExchange; + + private final ConcurrentHashMap<BindingImpl, BindingImpl> _bindings = new ConcurrentHashMap<BindingImpl, BindingImpl>(); + + + public BindingFactory(final VirtualHost vhost) + { + this(vhost,vhost.getExchangeRegistry().getDefaultExchange()); + } + + public BindingFactory(final DurableConfigurationStore.Source configSource, final Exchange defaultExchange) + { + _configSource = configSource; + _defaultExchange = defaultExchange; + if(configSource instanceof VirtualHost) + { + _virtualHost = (VirtualHost) configSource; + } + else + { + _virtualHost = null; + } + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + + + private final class BindingImpl extends Binding implements AMQQueue.Task, Exchange.Task, BindingConfig + { + private final BindingLogSubject _logSubject; + //TODO + private long _createTime = System.currentTimeMillis(); + + private BindingImpl(String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> arguments) + { + super(queue.getVirtualHost().getConfigStore().createId(),bindingKey, queue, exchange, arguments); + _logSubject = new BindingLogSubject(bindingKey,exchange,queue); + + } + + + public void doTask(final AMQQueue queue) throws AMQException + { + removeBinding(this); + } + + public void onClose(final Exchange exchange) + { + removeBinding(this); + } + + void logCreation() + { + CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(getArguments()), getArguments() != null && !getArguments().isEmpty())); + } + + void logDestruction() + { + CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED()); + } + + public String getOrigin() + { + return (String) getArguments().get("qpid.fed.origin"); + } + + public long getCreateTime() + { + return _createTime; + } + + public BindingConfigType getConfigType() + { + return BindingConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _virtualHost; + } + + public boolean isDurable() + { + return getQueue().isDurable() && getExchange().isDurable(); + } + + } + + + + public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) + { + return makeBinding(bindingKey, queue, exchange, arguments, false, false); + } + + + public boolean replaceBinding(final String bindingKey, + final AMQQueue queue, + final Exchange exchange, + final Map<String, Object> arguments) + { + return makeBinding(bindingKey, queue, exchange, arguments, false, true); + } + + private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments, boolean restore, boolean force) + { + assert queue != null; + if(bindingKey == null) + { + bindingKey = ""; + } + if(exchange == null) + { + exchange = _defaultExchange; + } + if(arguments == null) + { + arguments = Collections.EMPTY_MAP; + } + + BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); + BindingImpl existingMapping = _bindings.putIfAbsent(b,b); + if(existingMapping == null || force) + { + if(existingMapping != null) + { + removeBinding(existingMapping); + } + + if(b.isDurable() && !restore) + { + try + { + _configSource.getDurableConfigurationStore().bindQueue(exchange,new AMQShortString(bindingKey),queue,FieldTable.convertToFieldTable(arguments)); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + + queue.addQueueDeleteTask(b); + exchange.addCloseTask(b); + queue.addBinding(b); + exchange.addBinding(b); + getConfigStore().addConfiguredObject(b); + b.logCreation(); + return true; + } + else + { + return false; + } + + + } + + private ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> argumentMap) + { + makeBinding(bindingKey,queue,exchange,argumentMap,true, false); + } + + public void removeBinding(final Binding b) + { + removeBinding(b.getBindingKey(), b.getQueue(), b.getExchange(), b.getArguments()); + } + + + public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) + { + assert queue != null; + if(bindingKey == null) + { + bindingKey = ""; + } + if(exchange == null) + { + exchange = _defaultExchange; + } + if(arguments == null) + { + arguments = Collections.EMPTY_MAP; + } + + BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments)); + + if(b != null) + { + exchange.removeBinding(b); + queue.removeBinding(b); + exchange.removeCloseTask(b); + queue.removeQueueDeleteTask(b); + + if(b.isDurable()) + { + try + { + _configSource.getDurableConfigurationStore().unbindQueue(exchange, + new AMQShortString(bindingKey), + queue, + FieldTable.convertToFieldTable(arguments)); + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + b.logDestruction(); + getConfigStore().removeConfiguredObject(b); + + } + + return b; + } + + public Binding getBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) + { + assert queue != null; + if(bindingKey == null) + { + bindingKey = ""; + } + if(exchange == null) + { + exchange = _defaultExchange; + } + if(arguments == null) + { + arguments = Collections.EMPTY_MAP; + } + + BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); + return _bindings.get(b); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java new file mode 100644 index 0000000000..9414edcec4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfig.java @@ -0,0 +1,43 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.Map; + + +public interface BindingConfig extends ConfiguredObject<BindingConfigType, BindingConfig> +{ + + ExchangeConfig getExchange(); + + QueueConfig getQueue(); + + String getBindingKey(); + + Map<String, Object> getArguments(); + + String getOrigin(); + + long getCreateTime(); + + long getMatches(); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java new file mode 100644 index 0000000000..5cd064ff42 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BindingConfigType.java @@ -0,0 +1,112 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class BindingConfigType extends ConfigObjectType<BindingConfigType, BindingConfig> +{ + private static final List<BindingProperty<?>> BINDING_PROPERTIES = new ArrayList<BindingProperty<?>>(); + + public static interface BindingProperty<S> extends ConfigProperty<BindingConfigType, BindingConfig, S> + { + } + + private abstract static class BindingReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<BindingConfigType, BindingConfig, S> implements BindingProperty<S> + { + public BindingReadWriteProperty(String name) + { + super(name); + BINDING_PROPERTIES.add(this); + } + } + + private abstract static class BindingReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<BindingConfigType, BindingConfig, S> implements BindingProperty<S> + { + public BindingReadOnlyProperty(String name) + { + super(name); + BINDING_PROPERTIES.add(this); + } + } + + public static final BindingReadOnlyProperty<ExchangeConfig> EXCHANGE_PROPERTY = new BindingReadOnlyProperty<ExchangeConfig>("exchange") + { + public ExchangeConfig getValue(BindingConfig object) + { + return object.getExchange(); + } + }; + + public static final BindingReadOnlyProperty<QueueConfig> QUEUE_PROPERTY = new BindingReadOnlyProperty<QueueConfig>("queue") + { + public QueueConfig getValue(BindingConfig object) + { + return object.getQueue(); + } + }; + + public static final BindingReadOnlyProperty<String> BINDING_KEY_PROPERTY = new BindingReadOnlyProperty<String>("bindingKey") + { + public String getValue(BindingConfig object) + { + return object.getBindingKey(); + } + }; + + public static final BindingReadOnlyProperty<Map<String,Object>> ARGUMENTS = new BindingReadOnlyProperty<Map<String,Object>>("arguments") + { + public Map<String,Object> getValue(BindingConfig object) + { + return object.getArguments(); + } + }; + + public static final BindingReadOnlyProperty<String> ORIGIN_PROPERTY = new BindingReadOnlyProperty<String>("origin") + { + public String getValue(BindingConfig object) + { + return object.getOrigin(); + } + }; + + private static final BindingConfigType INSTANCE = new BindingConfigType(); + + private BindingConfigType() + { + } + + public Collection<BindingProperty<?>> getProperties() + { + return Collections.unmodifiableList(BINDING_PROPERTIES); + } + + public static BindingConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java new file mode 100644 index 0000000000..f999bf4578 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfig.java @@ -0,0 +1,50 @@ +/* + * + * 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.qpid.server.configuration; + +public interface BridgeConfig extends ConfiguredObject<BridgeConfigType, BridgeConfig> +{ + + boolean isDynamic(); + + boolean isQueueBridge(); + + boolean isLocalSource(); + + String getSource(); + + String getDestination(); + + String getKey(); + + String getTag(); + + String getExcludes(); + + LinkConfig getLink(); + + Integer getChannelId(); + + int getAckBatching(); + + long getCreateTime(); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java new file mode 100644 index 0000000000..a8d3cd9ec3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BridgeConfigType.java @@ -0,0 +1,169 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class BridgeConfigType extends ConfigObjectType<BridgeConfigType, BridgeConfig> +{ + private static final List<BridgeProperty<?>> BRIDGE_PROPERTIES = new ArrayList<BridgeProperty<?>>(); + + public static interface BridgeProperty<S> extends ConfigProperty<BridgeConfigType, BridgeConfig, S> + { + } + + private abstract static class BridgeReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<BridgeConfigType, BridgeConfig, S> implements BridgeProperty<S> + { + public BridgeReadWriteProperty(String name) + { + super(name); + BRIDGE_PROPERTIES.add(this); + } + } + + private abstract static class BridgeReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<BridgeConfigType, BridgeConfig, S> implements BridgeProperty<S> + { + public BridgeReadOnlyProperty(String name) + { + super(name); + BRIDGE_PROPERTIES.add(this); + } + } + + public static final BridgeReadOnlyProperty<LinkConfig> LINK_PROPERTY = new BridgeReadOnlyProperty<LinkConfig>("link") + { + public LinkConfig getValue(BridgeConfig object) + { + return object.getLink(); + } + }; + + public static final BridgeReadOnlyProperty<Integer> CHANNEL_ID_PROPERTY = new BridgeReadOnlyProperty<Integer>("channelId") + { + public Integer getValue(BridgeConfig object) + { + return object.getChannelId(); + } + }; + + public static final BridgeReadOnlyProperty<Boolean> DURABLE_PROPERTY = new BridgeReadOnlyProperty<Boolean>("durable") + { + public Boolean getValue(BridgeConfig object) + { + return object.isDurable(); + } + }; + + public static final BridgeReadOnlyProperty<String> SOURCE_PROPERTY = new BridgeReadOnlyProperty<String>("source") + { + public String getValue(BridgeConfig object) + { + return object.getSource(); + } + }; + + public static final BridgeReadOnlyProperty<String> DESTINATION_PROPERTY = new BridgeReadOnlyProperty<String>("destination") + { + public String getValue(BridgeConfig object) + { + return object.getDestination(); + } + }; + + public static final BridgeReadOnlyProperty<String> KEY_PROPERTY = new BridgeReadOnlyProperty<String>("key") + { + public String getValue(BridgeConfig object) + { + return object.getKey(); + } + }; + + public static final BridgeReadOnlyProperty<Boolean> QUEUE_BRIDGE_PROPERTY = new BridgeReadOnlyProperty<Boolean>("queueBridge") + { + public Boolean getValue(BridgeConfig object) + { + return object.isQueueBridge(); + } + }; + + public static final BridgeReadOnlyProperty<Boolean> LOCAL_SOURCE_PROPERTY = new BridgeReadOnlyProperty<Boolean>("localSource") + { + public Boolean getValue(BridgeConfig object) + { + return object.isLocalSource(); + } + }; + + public static final BridgeReadOnlyProperty<String> TAG_PROPERTY = new BridgeReadOnlyProperty<String>("tag") + { + public String getValue(BridgeConfig object) + { + return object.getTag(); + } + }; + + public static final BridgeReadOnlyProperty<String> EXCLUDES_PROPERTY = new BridgeReadOnlyProperty<String>("excludes") + { + public String getValue(BridgeConfig object) + { + return object.getExcludes(); + } + }; + + public static final BridgeReadOnlyProperty<Boolean> DYNAMIC_PROPERTY = new BridgeReadOnlyProperty<Boolean>("dynamic") + { + public Boolean getValue(BridgeConfig object) + { + return object.isDynamic(); + } + }; + + public static final BridgeReadOnlyProperty<Integer> ACK_BATCHING_PROPERTY = new BridgeReadOnlyProperty<Integer>("ackBatching") + { + public Integer getValue(BridgeConfig object) + { + return object.getAckBatching(); + } + }; + + + private static final BridgeConfigType INSTANCE = new BridgeConfigType(); + + private BridgeConfigType() + { + } + + public Collection<BridgeProperty<?>> getProperties() + { + return Collections.unmodifiableList(BRIDGE_PROPERTIES); + } + + public static BridgeConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java new file mode 100644 index 0000000000..4f74a72344 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfig.java @@ -0,0 +1,59 @@ +/* + * + * 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.qpid.server.configuration; + + +public interface BrokerConfig extends ConfiguredObject<BrokerConfigType,BrokerConfig> +{ + void setSystem(SystemConfig system); + + SystemConfig getSystem(); + + Integer getPort(); + + Integer getWorkerThreads(); + + Integer getMaxConnections(); + + Integer getConnectionBacklogLimit(); + + Long getStagingThreshold(); + + Integer getManagementPublishInterval(); + + String getVersion(); + + String getDataDirectory(); + + void addVirtualHost(VirtualHostConfig virtualHost); + + long getCreateTime(); + + void createBrokerConnection(String transport, + String host, + int port, + boolean durable, + String authMechanism, + String username, String password); + + String getFederationTag(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java new file mode 100644 index 0000000000..82b2fc82d2 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/BrokerConfigType.java @@ -0,0 +1,143 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.*; +import java.io.File; + +public final class BrokerConfigType extends ConfigObjectType<BrokerConfigType, BrokerConfig> +{ + private static final List<BrokerProperty<?>> BROKER_PROPERTIES = new ArrayList<BrokerProperty<?>>(); + + public static interface BrokerProperty<S> extends ConfigProperty<BrokerConfigType, BrokerConfig, S> + { + } + + private abstract static class BrokerReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<BrokerConfigType, BrokerConfig, S> implements BrokerProperty<S> + { + public BrokerReadWriteProperty(String name) + { + super(name); + BROKER_PROPERTIES.add(this); + } + } + + private abstract static class BrokerReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<BrokerConfigType, BrokerConfig, S> implements BrokerProperty<S> + { + public BrokerReadOnlyProperty(String name) + { + super(name); + BROKER_PROPERTIES.add(this); + } + } + + public static final BrokerReadOnlyProperty<SystemConfig> SYSTEM_PROPERTY = new BrokerReadOnlyProperty<SystemConfig>("system") + { + public SystemConfig getValue(BrokerConfig object) + { + return object.getSystem(); + } + }; + + public static final BrokerReadOnlyProperty<Integer> PORT_PROPERTY = new BrokerReadOnlyProperty<Integer>("port") + { + public Integer getValue(BrokerConfig object) + { + return object.getPort(); + } + }; + + public static final BrokerReadOnlyProperty<Integer> WORKER_THREADS_PROPERTY = new BrokerReadOnlyProperty<Integer>("workerThreads") + { + public Integer getValue(BrokerConfig object) + { + return object.getWorkerThreads(); + } + }; + + public static final BrokerReadOnlyProperty<Integer> MAX_CONNECTIONS_PROPERTY = new BrokerReadOnlyProperty<Integer>("maxConnections") + { + public Integer getValue(BrokerConfig object) + { + return object.getMaxConnections(); + } + }; + + public static final BrokerReadOnlyProperty<Integer> CONNECTION_BACKLOG_LIMIT_PROPERTY = new BrokerReadOnlyProperty<Integer>("connectionBacklog") + { + public Integer getValue(BrokerConfig object) + { + return object.getConnectionBacklogLimit(); + } + }; + + public static final BrokerReadOnlyProperty<Long> STAGING_THRESHOLD_PROPERTY = new BrokerReadOnlyProperty<Long>("stagingThreshold") + { + public Long getValue(BrokerConfig object) + { + return object.getStagingThreshold(); + } + }; + + public static final BrokerReadOnlyProperty<Integer> MANAGEMENT_PUBLISH_INTERVAL_PROPERTY = new BrokerReadOnlyProperty<Integer>("mgmtPublishInterval") + { + public Integer getValue(BrokerConfig object) + { + return object.getManagementPublishInterval(); + } + }; + + public static final BrokerReadOnlyProperty<String> VERSION_PROPERTY = new BrokerReadOnlyProperty<String>("version") + { + public String getValue(BrokerConfig object) + { + return object.getVersion(); + } + }; + + public static final BrokerReadOnlyProperty<String> DATA_DIR_PROPERTY = new BrokerReadOnlyProperty<String>("dataDirectory") + { + public String getValue(BrokerConfig object) + { + return object.getDataDirectory(); + } + }; + + private static final BrokerConfigType INSTANCE = new BrokerConfigType(); + + private BrokerConfigType() + { + } + + public Collection<BrokerProperty<?>> getProperties() + { + return Collections.unmodifiableList(BROKER_PROPERTIES); + } + + public static BrokerConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java new file mode 100644 index 0000000000..c45aaaf1ee --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigObjectType.java @@ -0,0 +1,30 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.Collection; + +public abstract class ConfigObjectType<T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T,C>> +{ + public abstract Collection<? extends ConfigProperty<T, C, ?>> getProperties(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java new file mode 100644 index 0000000000..2d88ba00a0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigProperty.java @@ -0,0 +1,66 @@ +/* + * + * 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.qpid.server.configuration; + +public interface ConfigProperty<T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T,C>, S> +{ + public String getName(); + + public S getValue(C object); + + public void setValue(C object, S value); + + public void clearValue(C object); + + public abstract static class ReadWriteConfigProperty<T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T,C>,S> implements ConfigProperty<T, C, S> + { + private final String _name; + + protected ReadWriteConfigProperty(String name) + { + _name = name; + } + + public final String getName() + { + return _name; + } + } + + public abstract static class ReadOnlyConfigProperty<T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T,C>, S> extends ReadWriteConfigProperty<T, C, S> + { + protected ReadOnlyConfigProperty(String name) + { + super(name); + } + + public final void setValue(C object, S value) + { + throw new UnsupportedOperationException("Cannot set value '"+getName()+"' as this property is read-only"); + } + + public final void clearValue(C object) + { + throw new UnsupportedOperationException("Cannot set value '"+getName()+"' as this property is read-only"); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java new file mode 100644 index 0000000000..572d886c18 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java @@ -0,0 +1,184 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.UUID; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; + +public class ConfigStore +{ + private ConcurrentHashMap<ConfigObjectType, ConcurrentHashMap<UUID, ConfiguredObject>> _typeMap = + new ConcurrentHashMap<ConfigObjectType, ConcurrentHashMap<UUID, ConfiguredObject>>(); + + private ConcurrentHashMap<ConfigObjectType, CopyOnWriteArrayList<ConfigEventListener>> _listenerMap = + new ConcurrentHashMap<ConfigObjectType, CopyOnWriteArrayList<ConfigEventListener>>(); + + private SystemConfig _root; + + private final AtomicLong _objectIdSource = new AtomicLong(0l); + + + public enum Event + { + CREATED, DELETED; + } + + public interface ConfigEventListener<T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T, C>> + { + void onEvent(C object, Event evt); + } + + private ConfigStore() + { + } + + public <T extends ConfigObjectType<T, C>, C extends ConfiguredObject<T, C>> ConfiguredObject<T, C> getConfiguredObject(ConfigObjectType<T,C> type, UUID id) + { + ConcurrentHashMap<UUID, ConfiguredObject> typeMap = _typeMap.get(type); + if(typeMap != null) + { + return typeMap.get(id); + } + else + { + return null; + } + + } + + public <T extends ConfigObjectType<T, C>, C extends ConfiguredObject<T, C>> Collection<? extends C> getConfiguredObjects(ConfigObjectType<T,C> type) + { + ConcurrentHashMap typeMap = _typeMap.get(type); + if(typeMap != null) + { + return typeMap.values(); + } + else + { + return Collections.EMPTY_LIST; + } + + } + + public <T extends ConfigObjectType<T, C>, C extends ConfiguredObject<T, C>> void addConfiguredObject(ConfiguredObject<T, C> object) + { + ConcurrentHashMap typeMap = _typeMap.get(object.getConfigType()); + if(typeMap == null) + { + typeMap = new ConcurrentHashMap(); + ConcurrentHashMap oldMap = _typeMap.putIfAbsent(object.getConfigType(), typeMap); + if(oldMap != null) + { + typeMap = oldMap; + } + + } + + typeMap.put(object.getId(), object); + sendEvent(Event.CREATED, object); + } + + + public <T extends ConfigObjectType<T, C>, C extends ConfiguredObject<T, C>> void removeConfiguredObject(ConfiguredObject<T, C> object) + { + ConcurrentHashMap typeMap = _typeMap.get(object.getConfigType()); + if(typeMap != null) + { + typeMap.remove(object.getId()); + sendEvent(Event.DELETED, object); + } + } + + public <T extends ConfigObjectType<T, C>, C extends ConfiguredObject<T, C>> void addConfigEventListener(T type, ConfigEventListener<T,C> listener) + { + CopyOnWriteArrayList listeners = _listenerMap.get(type); + if(listeners == null) + { + listeners = new CopyOnWriteArrayList(); + CopyOnWriteArrayList oldListeners = _listenerMap.putIfAbsent(type, listeners); + if(oldListeners != null) + { + listeners = oldListeners; + } + + } + + listeners.add(listener); + + } + + public <T extends ConfigObjectType<T, C>, C extends ConfiguredObject<T, C>> void removeConfigEventListener(T type, ConfigEventListener<T,C> listener) + { + CopyOnWriteArrayList listeners = _listenerMap.get(type); + if(listeners != null) + { + listeners.remove(listener); + } + } + + private void sendEvent(Event e, ConfiguredObject o) + { + CopyOnWriteArrayList<ConfigEventListener> listeners = _listenerMap.get(o.getConfigType()); + if(listeners != null) + { + for(ConfigEventListener listener : listeners) + { + listener.onEvent(o, e); + } + } + } + + public synchronized boolean setRoot(SystemConfig object) + { + if(_root == null) + { + _root = object; + addConfiguredObject(object); + return true; + } + else + { + return false; + } + } + + public UUID createId() + { + return new UUID(0l, _objectIdSource.getAndIncrement()); + } + + + public SystemConfig getRoot() + { + return _root; + } + + public static ConfigStore newInstance() + { + return new ConfigStore(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java new file mode 100644 index 0000000000..dd116ea29a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfiguredObject.java @@ -0,0 +1,36 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.UUID; + +public interface ConfiguredObject<T extends ConfigObjectType<T,C>, C extends ConfiguredObject<T, C>> +{ + public UUID getId(); + + public T getConfigType(); + + public ConfiguredObject getParent(); + + public boolean isDurable(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java new file mode 100644 index 0000000000..95fb7d39a1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfig.java @@ -0,0 +1,45 @@ +/* + * + * 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.qpid.server.configuration; + +public interface ConnectionConfig extends ConfiguredObject<ConnectionConfigType, ConnectionConfig> +{ + VirtualHostConfig getVirtualHost(); + + String getAddress(); + + Boolean isIncoming(); + + Boolean isSystemConnection(); + + Boolean isFederationLink(); + + String getAuthId(); + + String getRemoteProcessName(); + + Integer getRemotePID(); + + Integer getRemoteParentPID(); + + ConfigStore getConfigStore(); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java new file mode 100644 index 0000000000..9750b12dea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConnectionConfigType.java @@ -0,0 +1,145 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class ConnectionConfigType extends ConfigObjectType<ConnectionConfigType, ConnectionConfig> +{ + private static final List<ConnectionProperty<?>> CONNECTION_PROPERTIES = new ArrayList<ConnectionProperty<?>>(); + + public static interface ConnectionProperty<S> extends ConfigProperty<ConnectionConfigType, ConnectionConfig, S> + { + } + + private abstract static class ConnectionReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<ConnectionConfigType, ConnectionConfig, S> implements ConnectionProperty<S> + { + public ConnectionReadWriteProperty(String name) + { + super(name); + CONNECTION_PROPERTIES.add(this); + } + } + + private abstract static class ConnectionReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<ConnectionConfigType, ConnectionConfig, S> implements ConnectionProperty<S> + { + public ConnectionReadOnlyProperty(String name) + { + super(name); + CONNECTION_PROPERTIES.add(this); + } + } + + public static final ConnectionReadOnlyProperty<VirtualHostConfig> VIRTUAL_HOST_PROPERTY = new ConnectionReadOnlyProperty<VirtualHostConfig>("virtualHost") + { + public VirtualHostConfig getValue(ConnectionConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final ConnectionReadOnlyProperty<String> ADDRESS_PROPERTY = new ConnectionReadOnlyProperty<String>("address") + { + public String getValue(ConnectionConfig object) + { + return object.getAddress(); + } + }; + + public static final ConnectionReadOnlyProperty<Boolean> INCOMING_PROPERTY = new ConnectionReadOnlyProperty<Boolean>("incoming") + { + public Boolean getValue(ConnectionConfig object) + { + return object.isIncoming(); + } + }; + + public static final ConnectionReadOnlyProperty<Boolean> SYSTEM_CONNECTION_PROPERTY = new ConnectionReadOnlyProperty<Boolean>("systemConnection") + { + public Boolean getValue(ConnectionConfig object) + { + return object.isSystemConnection(); + } + }; + + public static final ConnectionReadOnlyProperty<Boolean> FEDERATION_LINK_PROPERTY = new ConnectionReadOnlyProperty<Boolean>("federationLink") + { + public Boolean getValue(ConnectionConfig object) + { + return object.isFederationLink(); + } + }; + + public static final ConnectionReadOnlyProperty<String> AUTH_ID_PROPERTY = new ConnectionReadOnlyProperty<String>("authId") + { + public String getValue(ConnectionConfig object) + { + return object.getAuthId(); + } + }; + + public static final ConnectionReadOnlyProperty<String> REMOTE_PROCESS_NAME_PROPERTY = new ConnectionReadOnlyProperty<String>("remoteProcessName") + { + public String getValue(ConnectionConfig object) + { + return object.getRemoteProcessName(); + } + }; + + + public static final ConnectionReadOnlyProperty<Integer> REMOTE_PID_PROPERTY = new ConnectionReadOnlyProperty<Integer>("remotePid") + { + public Integer getValue(ConnectionConfig object) + { + return object.getRemotePID(); + } + }; + + public static final ConnectionReadOnlyProperty<Integer> REMOTE_PARENT_PID_PROPERTY = new ConnectionReadOnlyProperty<Integer>("remoteParentPid") + { + public Integer getValue(ConnectionConfig object) + { + return object.getRemoteParentPID(); + } + }; + + private static final ConnectionConfigType INSTANCE = new ConnectionConfigType(); + + private ConnectionConfigType() + { + } + + public Collection<ConnectionProperty<?>> getProperties() + { + return Collections.unmodifiableList(CONNECTION_PROPERTIES); + } + + public static ConnectionConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java new file mode 100644 index 0000000000..40dc88c28c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java @@ -0,0 +1,57 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.Map; + + +public interface ExchangeConfig extends ConfiguredObject<ExchangeConfigType, ExchangeConfig> +{ + VirtualHostConfig getVirtualHost(); + + String getName(); + + ExchangeType getType(); + + boolean isAutoDelete(); + + ExchangeConfig getAlternateExchange(); + + Map<String, Object> getArguments(); + + + long getBindingCount(); + + long getBindingCountHigh(); + + long getMsgReceives(); + + long getMsgRoutes(); + + long getByteReceives(); + + long getByteRoutes(); + + long getCreateTime(); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java new file mode 100644 index 0000000000..2095301ad6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfigType.java @@ -0,0 +1,113 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class ExchangeConfigType extends ConfigObjectType<ExchangeConfigType, ExchangeConfig> +{ + private static final List<ExchangeProperty<?>> EXCHANGE_PROPERTIES = new ArrayList<ExchangeProperty<?>>(); + + public static interface ExchangeProperty<S> extends ConfigProperty<ExchangeConfigType, ExchangeConfig, S> + { + } + + private abstract static class ExchangeReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<ExchangeConfigType, ExchangeConfig, S> implements ExchangeProperty<S> + { + public ExchangeReadWriteProperty(String name) + { + super(name); + EXCHANGE_PROPERTIES.add(this); + } + } + + private abstract static class ExchangeReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<ExchangeConfigType, ExchangeConfig, S> implements ExchangeProperty<S> + { + public ExchangeReadOnlyProperty(String name) + { + super(name); + EXCHANGE_PROPERTIES.add(this); + } + } + + public static final ExchangeReadOnlyProperty<VirtualHostConfig> VIRTUAL_HOST_PROPERTY = new ExchangeReadOnlyProperty<VirtualHostConfig>("virtualHost") + { + public VirtualHostConfig getValue(ExchangeConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final ExchangeReadOnlyProperty<String> NAME_PROPERTY = new ExchangeReadOnlyProperty<String>("name") + { + public String getValue(ExchangeConfig object) + { + return object.getName(); + } + }; + + public static final ExchangeReadOnlyProperty<Boolean> AUTODELETE_PROPERTY = new ExchangeReadOnlyProperty<Boolean>("autodelete") + { + public Boolean getValue(ExchangeConfig object) + { + return object.isAutoDelete(); + } + }; + + + public static final ExchangeReadOnlyProperty<ExchangeConfig> ALTERNATE_EXCHANGE_PROPERTY = new ExchangeReadOnlyProperty<ExchangeConfig>("alternateExchange") + { + public ExchangeConfig getValue(ExchangeConfig object) + { + return object.getAlternateExchange(); + } + }; + + public static final ExchangeReadOnlyProperty<Map<String,Object>> ARGUMENTS = new ExchangeReadOnlyProperty<Map<String,Object>>("arguments") + { + public Map<String,Object> getValue(ExchangeConfig object) + { + return object.getArguments(); + } + }; + + private static final ExchangeConfigType INSTANCE = new ExchangeConfigType(); + + private ExchangeConfigType() + { + } + + public Collection<ExchangeProperty<?>> getProperties() + { + return Collections.unmodifiableList(EXCHANGE_PROPERTIES); + } + + public static ExchangeConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java new file mode 100644 index 0000000000..82e0647917 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java @@ -0,0 +1,59 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.Map; + + +public interface LinkConfig extends ConfiguredObject<LinkConfigType, LinkConfig> +{ + VirtualHostConfig getVirtualHost(); + + + String getTransport(); + + String getHost(); + + int getPort(); + + String getRemoteVhost(); + + String getAuthMechanism(); + + String getUsername(); + + String getPassword(); + + void close(); + + long getCreateTime(); + + void createBridge(boolean durable, + boolean dynamic, + boolean srcIsQueue, + boolean srcIsLocal, + String src, + String dest, + String key, String tag, String excludes); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java new file mode 100644 index 0000000000..4dc46b70c9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfigType.java @@ -0,0 +1,136 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class LinkConfigType extends ConfigObjectType<LinkConfigType, LinkConfig> +{ + private static final List<LinkProperty<?>> LINK_PROPERTIES = new ArrayList<LinkProperty<?>>(); + + public static interface LinkProperty<S> extends ConfigProperty<LinkConfigType, LinkConfig, S> + { + } + + private abstract static class LinkReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<LinkConfigType, LinkConfig, S> implements LinkProperty<S> + { + public LinkReadWriteProperty(String name) + { + super(name); + LINK_PROPERTIES.add(this); + } + } + + private abstract static class LinkReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<LinkConfigType, LinkConfig, S> implements LinkProperty<S> + { + public LinkReadOnlyProperty(String name) + { + super(name); + LINK_PROPERTIES.add(this); + } + } + + public static final LinkReadOnlyProperty<VirtualHostConfig> VIRTUAL_HOST_PROPERTY = new LinkReadOnlyProperty<VirtualHostConfig>("virtualHost") + { + public VirtualHostConfig getValue(LinkConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final LinkReadOnlyProperty<String> TRANSPORT_PROPERTY = new LinkReadOnlyProperty<String>("transport") + { + public String getValue(LinkConfig object) + { + return object.getTransport(); + } + }; + + public static final LinkReadOnlyProperty<String> HOST_PROPERTY = new LinkReadOnlyProperty<String>("host") + { + public String getValue(LinkConfig object) + { + return object.getHost(); + } + }; + + public static final LinkReadOnlyProperty<Integer> PORT_PROPERTY = new LinkReadOnlyProperty<Integer>("host") + { + public Integer getValue(LinkConfig object) + { + return object.getPort(); + } + }; + + public static final LinkReadOnlyProperty<String> REMOTE_VHOST_PROPERTY = new LinkReadOnlyProperty<String>("remoteVhost") + { + public String getValue(LinkConfig object) + { + return object.getRemoteVhost(); + } + }; + + public static final LinkReadOnlyProperty<String> AUTH_MECHANISM_PROPERTY = new LinkReadOnlyProperty<String>("authMechanism") + { + public String getValue(LinkConfig object) + { + return object.getAuthMechanism(); + } + }; + + public static final LinkReadOnlyProperty<String> USERNAME_PROPERTY = new LinkReadOnlyProperty<String>("username") + { + public String getValue(LinkConfig object) + { + return object.getUsername(); + } + }; + + public static final LinkReadOnlyProperty<String> PASSWORD_PROPERTY = new LinkReadOnlyProperty<String>("password") + { + public String getValue(LinkConfig object) + { + return object.getPassword(); + } + }; + + private static final LinkConfigType INSTANCE = new LinkConfigType(); + + private LinkConfigType() + { + } + + public Collection<LinkProperty<?>> getProperties() + { + return Collections.unmodifiableList(LINK_PROPERTIES); + } + + public static LinkConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java new file mode 100644 index 0000000000..a451091fee --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfig.java @@ -0,0 +1,72 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.Map; + + +public interface QueueConfig extends ConfiguredObject<QueueConfigType, QueueConfig> +{ + VirtualHostConfig getVirtualHost(); + + String getName(); + + boolean isExclusive(); + + boolean isAutoDelete(); + + ExchangeConfig getAlternateExchange(); + + Map<String, Object> getArguments(); + + long getReceivedMessageCount(); + + int getMessageCount(); + + long getQueueDepth(); + + int getConsumerCount(); + + int getBindingCount(); + + ConfigStore getConfigStore(); + + long getMessageDequeueCount(); + + long getTotalEnqueueSize(); + + long getTotalDequeueSize(); + + int getBindingCountHigh(); + + long getPersistentByteEnqueues(); + + long getPersistentByteDequeues(); + + long getPersistentMsgEnqueues(); + + long getPersistentMsgDequeues(); + + void purge(long request); + + long getCreateTime(); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java new file mode 100644 index 0000000000..a794ed9747 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfigType.java @@ -0,0 +1,121 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class QueueConfigType extends ConfigObjectType<QueueConfigType, QueueConfig> +{ + private static final List<QueueProperty<?>> QUEUE_PROPERTIES = new ArrayList<QueueProperty<?>>(); + + public static interface QueueProperty<S> extends ConfigProperty<QueueConfigType, QueueConfig, S> + { + } + + private abstract static class QueueReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<QueueConfigType, QueueConfig, S> implements QueueProperty<S> + { + public QueueReadWriteProperty(String name) + { + super(name); + QUEUE_PROPERTIES.add(this); + } + } + + private abstract static class QueueReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<QueueConfigType, QueueConfig, S> implements QueueProperty<S> + { + public QueueReadOnlyProperty(String name) + { + super(name); + QUEUE_PROPERTIES.add(this); + } + } + + public static final QueueReadOnlyProperty<VirtualHostConfig> VISTUAL_HOST_PROPERTY = new QueueReadOnlyProperty<VirtualHostConfig>("virtualHost") + { + public VirtualHostConfig getValue(QueueConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final QueueReadOnlyProperty<String> NAME_PROPERTY = new QueueReadOnlyProperty<String>("name") + { + public String getValue(QueueConfig object) + { + return object.getName(); + } + }; + + public static final QueueReadOnlyProperty<Boolean> AUTODELETE_PROPERTY = new QueueReadOnlyProperty<Boolean>("autodelete") + { + public Boolean getValue(QueueConfig object) + { + return object.isAutoDelete(); + } + }; + + public static final QueueReadOnlyProperty<Boolean> EXCLUSIVE_PROPERTY = new QueueReadOnlyProperty<Boolean>("exclusive") + { + public Boolean getValue(QueueConfig object) + { + return object.isExclusive(); + } + }; + + public static final QueueReadOnlyProperty<ExchangeConfig> ALTERNATE_EXCHANGE_PROPERTY = new QueueReadOnlyProperty<ExchangeConfig>("alternateExchange") + { + public ExchangeConfig getValue(QueueConfig object) + { + return object.getAlternateExchange(); + } + }; + + public static final QueueReadOnlyProperty<Map<String,Object>> ARGUMENTS = new QueueReadOnlyProperty<Map<String,Object>>("arguments") + { + public Map<String,Object> getValue(QueueConfig object) + { + return object.getArguments(); + } + }; + + + private static final QueueConfigType INSTANCE = new QueueConfigType(); + + private QueueConfigType() + { + } + + public Collection<QueueProperty<?>> getProperties() + { + return Collections.unmodifiableList(QUEUE_PROPERTIES); + } + + public static QueueConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 5c73e353de..44759bb4b8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -118,4 +118,13 @@ public class QueueConfiguration return _config.getLong("flowResumeCapacity", _vHostConfig.getFlowResumeCapacity()); } + public boolean isLVQ() + { + return _config.getBoolean("lvq", false); + } + + public String getLVQKey() + { + return _config.getString("lvqKey", null); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java new file mode 100644 index 0000000000..ae01ab25ea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfig.java @@ -0,0 +1,41 @@ +/* + * + * 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.qpid.server.configuration; + +public interface SessionConfig extends ConfiguredObject<SessionConfigType, SessionConfig> +{ + VirtualHostConfig getVirtualHost(); + + String getSessionName(); + + int getChannel(); + + ConnectionConfig getConnectionConfig(); + + boolean isAttached(); + + long getDetachedLifespan(); + + Long getExpiryTime(); + + Long getMaxClientRate(); +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java new file mode 100644 index 0000000000..97cf275575 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SessionConfigType.java @@ -0,0 +1,136 @@ +/* + * + * 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.qpid.server.configuration; + +import org.apache.qpid.server.exchange.ExchangeType; + +import java.util.*; + +public final class SessionConfigType extends ConfigObjectType<SessionConfigType, SessionConfig> +{ + private static final List<SessionProperty<?>> SESSION_PROPERTIES = new ArrayList<SessionProperty<?>>(); + + public static interface SessionProperty<S> extends ConfigProperty<SessionConfigType, SessionConfig, S> + { + } + + private abstract static class SessionReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<SessionConfigType, SessionConfig, S> implements SessionProperty<S> + { + public SessionReadWriteProperty(String name) + { + super(name); + SESSION_PROPERTIES.add(this); + } + } + + private abstract static class SessionReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<SessionConfigType, SessionConfig, S> implements SessionProperty<S> + { + public SessionReadOnlyProperty(String name) + { + super(name); + SESSION_PROPERTIES.add(this); + } + } + + public static final SessionReadOnlyProperty<VirtualHostConfig> VIRTUAL_HOST_PROPERTY = new SessionReadOnlyProperty<VirtualHostConfig>("virtualHost") + { + public VirtualHostConfig getValue(SessionConfig object) + { + return object.getVirtualHost(); + } + }; + + public static final SessionReadOnlyProperty<String> NAME_PROPERTY = new SessionReadOnlyProperty<String>("name") + { + public String getValue(SessionConfig object) + { + return object.getSessionName(); + } + }; + + public static final SessionReadOnlyProperty<Integer> CHANNEL_ID_PROPERTY = new SessionReadOnlyProperty<Integer>("channelId") + { + public Integer getValue(SessionConfig object) + { + return object.getChannel(); + } + }; + + public static final SessionReadOnlyProperty<ConnectionConfig> CONNECTION_PROPERTY = new SessionReadOnlyProperty<ConnectionConfig>("connection") + { + public ConnectionConfig getValue(SessionConfig object) + { + return object.getConnectionConfig(); + } + }; + + public static final SessionReadOnlyProperty<Boolean> ATTACHED_PROPERTY = new SessionReadOnlyProperty<Boolean>("attached") + { + public Boolean getValue(SessionConfig object) + { + return object.isAttached(); + } + }; + + public static final SessionReadOnlyProperty<Long> DETACHED_LIFESPAN_PROPERTY = new SessionReadOnlyProperty<Long>("detachedLifespan") + { + public Long getValue(SessionConfig object) + { + return object.getDetachedLifespan(); + } + }; + + public static final SessionReadOnlyProperty<Long> EXPIRE_TIME_PROPERTY = new SessionReadOnlyProperty<Long>("expireTime") + { + public Long getValue(SessionConfig object) + { + return object.getExpiryTime(); + } + }; + + public static final SessionReadOnlyProperty<Long> MAX_CLIENT_RATE_PROPERTY = new SessionReadOnlyProperty<Long>("maxClientRate") + { + public Long getValue(SessionConfig object) + { + return object.getMaxClientRate(); + } + }; + + private static final SessionConfigType INSTANCE = new SessionConfigType(); + + private SessionConfigType() + { + } + + public Collection<SessionProperty<?>> getProperties() + { + return Collections.unmodifiableList(SESSION_PROPERTIES); + } + + public static SessionConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java new file mode 100644 index 0000000000..985ecb2be9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfig.java @@ -0,0 +1,47 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.Map; + + +public interface SubscriptionConfig extends ConfiguredObject<SubscriptionConfigType, SubscriptionConfig> +{ + + SessionConfig getSessionConfig(); + + QueueConfig getQueue(); + + String getName(); + + Map<String, Object> getArguments(); + + String getCreditMode(); + + boolean isBrowsing(); + + boolean isExclusive(); + + boolean isExplicitAcknowledge(); + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java new file mode 100644 index 0000000000..99d3273b55 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SubscriptionConfigType.java @@ -0,0 +1,136 @@ +/* + * + * 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.qpid.server.configuration; + + +import java.util.*; + +public final class SubscriptionConfigType extends ConfigObjectType<SubscriptionConfigType, SubscriptionConfig> +{ + private static final List<SubscriptionProperty<?>> SUBSCRIPTION_PROPERTIES = new ArrayList<SubscriptionProperty<?>>(); + + public static interface SubscriptionProperty<S> extends ConfigProperty<SubscriptionConfigType, SubscriptionConfig, S> + { + } + + private abstract static class SubscriptionReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<SubscriptionConfigType, SubscriptionConfig, S> implements SubscriptionProperty<S> + { + public SubscriptionReadWriteProperty(String name) + { + super(name); + SUBSCRIPTION_PROPERTIES.add(this); + } + } + + private abstract static class SubscriptionReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<SubscriptionConfigType, SubscriptionConfig, S> implements SubscriptionProperty<S> + { + public SubscriptionReadOnlyProperty(String name) + { + super(name); + SUBSCRIPTION_PROPERTIES.add(this); + } + } + + public static final SubscriptionReadOnlyProperty<SessionConfig> SESSION_PROPERTY = new SubscriptionReadOnlyProperty<SessionConfig>("session") + { + public SessionConfig getValue(SubscriptionConfig object) + { + return object.getSessionConfig(); + } + }; + + public static final SubscriptionReadOnlyProperty<QueueConfig> QUEUE_PROPERTY = new SubscriptionReadOnlyProperty<QueueConfig>("queue") + { + public QueueConfig getValue(SubscriptionConfig object) + { + return object.getQueue(); + } + }; + + public static final SubscriptionReadOnlyProperty<String> NAME_PROPERTY = new SubscriptionReadOnlyProperty<String>("name") + { + public String getValue(SubscriptionConfig object) + { + return object.getName(); + } + }; + + public static final SubscriptionReadOnlyProperty<Map<String,Object>> ARGUMENTS = new SubscriptionReadOnlyProperty<Map<String,Object>>("arguments") + { + public Map<String,Object> getValue(SubscriptionConfig object) + { + return object.getArguments(); + } + }; + + public static final SubscriptionReadOnlyProperty<String> CREDIT_MODE_PROPERTY = new SubscriptionReadOnlyProperty<String>("creditMode") + { + public String getValue(SubscriptionConfig object) + { + return object.getCreditMode(); + } + }; + + public static final SubscriptionReadOnlyProperty<Boolean> BROWSING_PROPERTY = new SubscriptionReadOnlyProperty<Boolean>("browsing") + { + public Boolean getValue(SubscriptionConfig object) + { + return object.isBrowsing(); + } + }; + + public static final SubscriptionReadOnlyProperty<Boolean> EXCLUSIVE_PROPERTY = new SubscriptionReadOnlyProperty<Boolean>("exclusive") + { + public Boolean getValue(SubscriptionConfig object) + { + return object.isExclusive(); + } + }; + + public static final SubscriptionReadOnlyProperty<Boolean> EXPLICIT_ACK_PROPERTY = new SubscriptionReadOnlyProperty<Boolean>("explicitAck") + { + public Boolean getValue(SubscriptionConfig object) + { + return object.isExplicitAcknowledge(); + } + }; + + private static final SubscriptionConfigType INSTANCE = new SubscriptionConfigType(); + + private SubscriptionConfigType() + { + } + + public Collection<SubscriptionProperty<?>> getProperties() + { + return Collections.unmodifiableList(SUBSCRIPTION_PROPERTIES); + } + + + public static SubscriptionConfigType getInstance() + { + return INSTANCE; + } + + + +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java new file mode 100644 index 0000000000..1e722ea191 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfig.java @@ -0,0 +1,44 @@ +/* + * + * 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.qpid.server.configuration; + +public interface SystemConfig extends ConfiguredObject<SystemConfigType,SystemConfig> +{ + String getName(); + + String getOperatingSystemName(); + + String getNodeName(); + + + String getOSRelease(); + + String getOSVersion(); + + String getOSArchitecture(); + + void addBroker(BrokerConfig broker); + + void removeBroker(BrokerConfig broker); + + long getCreateTime(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java new file mode 100644 index 0000000000..09ebb07105 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigImpl.java @@ -0,0 +1,136 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.UUID; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class SystemConfigImpl implements SystemConfig +{ + private static final String OS_NAME = System.getProperty("os.name"); + private static final String OS_ARCH = System.getProperty("os.arch"); + private static final String OS_VERSION = System.getProperty("os.version"); + + private final UUID _id; + private String _name; + + private final String _host; + + private final Map<UUID, BrokerConfig> _brokers = new ConcurrentHashMap<UUID, BrokerConfig>(); + + private final long _createTime = System.currentTimeMillis(); + private final ConfigStore _store; + + public SystemConfigImpl(ConfigStore store) + { + this(store.createId(), store); + } + + public SystemConfigImpl(UUID id, ConfigStore store) + { + _id = id; + _store = store; + String host; + try + { + InetAddress addr = InetAddress.getLocalHost(); + host = addr.getHostName(); + } + catch (UnknownHostException e) + { + host="localhost"; + } + _host = host; + } + + public String getName() + { + return _name; + } + + public String getOperatingSystemName() + { + return OS_NAME; + } + + public String getNodeName() + { + return _host; + } + + public String getOSRelease() + { + return OS_VERSION; + } + + public String getOSVersion() + { + return ""; + } + + public String getOSArchitecture() + { + return OS_ARCH; + } + + public UUID getId() + { + return _id; + } + + public SystemConfigType getConfigType() + { + return SystemConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return null; + } + + public boolean isDurable() + { + return false; + } + + public void addBroker(final BrokerConfig broker) + { + broker.setSystem(this); + _store.addConfiguredObject(broker); + _brokers.put(broker.getId(), broker); + } + + public void removeBroker(final BrokerConfig broker) + { + _brokers.remove(broker.getId()); + _store.removeConfiguredObject(broker); + } + + public long getCreateTime() + { + return _createTime; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java new file mode 100644 index 0000000000..f5aabd2345 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/SystemConfigType.java @@ -0,0 +1,128 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.*; + +public final class SystemConfigType extends ConfigObjectType<SystemConfigType, SystemConfig> +{ + private static final List<SystemProperty<?>> SYSTEM_PROPERTIES = new ArrayList<SystemProperty<?>>(); + + public static interface SystemProperty<S> extends ConfigProperty<SystemConfigType, SystemConfig, S> + { + } + + private abstract static class SystemReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<SystemConfigType, SystemConfig, S> implements SystemProperty<S> + { + public SystemReadWriteProperty(String name) + { + super(name); + SYSTEM_PROPERTIES.add(this); + } + } + + private abstract static class SystemReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<SystemConfigType, SystemConfig, S> implements SystemProperty<S> + { + public SystemReadOnlyProperty(String name) + { + super(name); + SYSTEM_PROPERTIES.add(this); + } + } + + public static final SystemReadOnlyProperty<String> NAME_PROPERTY = new SystemReadOnlyProperty<String>("name") + { + public String getValue(SystemConfig object) + { + return object.getName(); + } + }; + + public static final SystemReadOnlyProperty<UUID> ID_PROPERTY = new SystemReadOnlyProperty<UUID>("id") + { + public UUID getValue(SystemConfig object) + { + return object.getId(); + } + }; + + public static final SystemReadOnlyProperty<String> OS_NAME_PROPERTY = new SystemReadOnlyProperty<String>("osName") + { + public String getValue(SystemConfig object) + { + return object.getOperatingSystemName(); + } + }; + + public static final SystemReadOnlyProperty<String> NODE_NAME_PROPERTY = new SystemReadOnlyProperty<String>("nodeName") + { + public String getValue(SystemConfig object) + { + return object.getNodeName(); + } + }; + + public static final SystemReadOnlyProperty<String> RELEASE_PROPERTY = new SystemReadOnlyProperty<String>("release") + { + public String getValue(SystemConfig object) + { + return object.getOSRelease(); + } + }; + + public static final SystemReadOnlyProperty<String> VERSION_PROPERTY = new SystemReadOnlyProperty<String>("version") + { + public String getValue(SystemConfig object) + { + return object.getOSVersion(); + } + }; + + public static final SystemReadOnlyProperty<String> MACHINE_PROPERTY = new SystemReadOnlyProperty<String>("machine") + { + public String getValue(SystemConfig object) + { + return object.getOSArchitecture(); + } + }; + + private static final SystemConfigType INSTANCE = new SystemConfigType(); + + private SystemConfigType() + { + } + + public Collection<SystemProperty<?>> getProperties() + { + return Collections.unmodifiableList(SYSTEM_PROPERTIES); + } + + + + public static SystemConfigType getInstance() + { + return INSTANCE; + } + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java new file mode 100644 index 0000000000..9431e5175f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfig.java @@ -0,0 +1,36 @@ +/* + * + * 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.qpid.server.configuration; + +public interface VirtualHostConfig extends ConfiguredObject<VirtualHostConfigType, VirtualHostConfig> +{ + String getName(); + + BrokerConfig getBroker(); + + String getFederationTag(); + + void setBroker(BrokerConfig brokerConfig); + + long getCreateTime(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java new file mode 100644 index 0000000000..96682335bf --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfigType.java @@ -0,0 +1,96 @@ +/* + * + * 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.qpid.server.configuration; + +import java.util.*; + +public class VirtualHostConfigType extends ConfigObjectType<VirtualHostConfigType, VirtualHostConfig> +{ + private static final List<VirtualHostProperty<?>> VIRTUAL_HOST_PROPERTIES = new ArrayList<VirtualHostProperty<?>>(); + private static final VirtualHostConfigType INSTANCE = new VirtualHostConfigType(); +public static interface VirtualHostProperty<S> extends ConfigProperty<VirtualHostConfigType, VirtualHostConfig, S> + { + } + + private abstract static class VirtualHostReadWriteProperty<S> extends ConfigProperty.ReadWriteConfigProperty<VirtualHostConfigType, VirtualHostConfig, S> implements VirtualHostProperty<S> + { + public VirtualHostReadWriteProperty(String name) + { + super(name); + VIRTUAL_HOST_PROPERTIES.add(this); + } + } + + private abstract static class VirtualHostReadOnlyProperty<S> extends ConfigProperty.ReadOnlyConfigProperty<VirtualHostConfigType, VirtualHostConfig, S> implements VirtualHostProperty<S> + { + public VirtualHostReadOnlyProperty(String name) + { + super(name); + VIRTUAL_HOST_PROPERTIES.add(this); + } + } + + + public static final VirtualHostReadOnlyProperty<String> NAME_PROPERTY = new VirtualHostReadOnlyProperty<String>("name") + { + public String getValue(VirtualHostConfig object) + { + return object.getName(); + } + }; + + + public static final VirtualHostReadOnlyProperty<BrokerConfig> BROKER_PROPERTY = new VirtualHostReadOnlyProperty<BrokerConfig>("broker") + { + public BrokerConfig getValue(VirtualHostConfig object) + { + return object.getBroker(); + } + }; + + public static final VirtualHostReadOnlyProperty<String> FEDERATION_TAG_PROPERTY = new VirtualHostReadOnlyProperty<String>("federationTag") + { + public String getValue(VirtualHostConfig object) + { + return object.getFederationTag(); + } + }; + + + + public Collection<? extends ConfigProperty<VirtualHostConfigType, VirtualHostConfig, ?>> getProperties() + { + return Collections.unmodifiableList(VIRTUAL_HOST_PROPERTIES); + } + + + private VirtualHostConfigType() + { + } + + public static VirtualHostConfigType getInstance() + { + return INSTANCE; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 07f33b4a8f..32b95ff742 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -20,51 +20,57 @@ */ package org.apache.qpid.server.exchange; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.JMException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.ArrayType; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ExchangeConfigType; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ExchangeMessages; +import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.ExchangeMessages; -import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.log4j.Logger; +import javax.management.JMException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; public abstract class AbstractExchange implements Exchange, Managable { + + private AMQShortString _name; + private final AtomicBoolean _closed = new AtomicBoolean(); private Exchange _alternateExchange; protected boolean _durable; - protected String _exchangeType; protected int _ticket; private VirtualHost _virtualHost; - protected ExchangeMBean _exchangeMbean; + private final List<Exchange.Task> _closeTaskList = new CopyOnWriteArrayList<Exchange.Task>(); + + + protected AbstractExchangeMBean _exchangeMbean; /** * Whether the exchange is automatically deleted once all queues have detached from it @@ -75,95 +81,49 @@ public abstract class AbstractExchange implements Exchange, Managable private LogSubject _logSubject; private Map<ExchangeReferrer,Object> _referrers = new ConcurrentHashMap<ExchangeReferrer,Object>(); - /** - * Abstract MBean class. This has some of the methods implemented from - * management intrerface for exchanges. Any implementaion of an - * Exchange MBean should extend this class. - */ - protected abstract class ExchangeMBean extends AMQManagedObject implements ManagedExchange - { - // open mbean data types for representing exchange bindings - protected OpenType[] _bindingItemTypes; - protected CompositeType _bindingDataType; - protected TabularType _bindinglistDataType; - protected TabularDataSupport _bindingList; + private final CopyOnWriteArrayList<Binding> _bindings = new CopyOnWriteArrayList<Binding>(); + private final ExchangeType<? extends Exchange> _type; + private UUID _id; + private final AtomicInteger _bindingCountHigh = new AtomicInteger(); + private final AtomicLong _receivedMessageCount = new AtomicLong(); + private final AtomicLong _receivedMessageSize = new AtomicLong(); + private final AtomicLong _routedMessageCount = new AtomicLong(); + private final AtomicLong _routedMessageSize = new AtomicLong(); + private final CopyOnWriteArrayList<Exchange.BindingListener> _listeners = new CopyOnWriteArrayList<Exchange.BindingListener>(); +/* +======= public ExchangeMBean() throws NotCompliantMBeanException { super(ManagedExchange.class, ManagedExchange.TYPE); } +>>>>>>> .r902547 +*/ - protected void init() throws OpenDataException - { - _bindingItemTypes = new OpenType[2]; - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, TABULAR_UNIQUE_INDEX); - } - - public ManagedObject getParentObject() - { - return _virtualHost.getManagedObject(); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public String getExchangeType() - { - return _exchangeType; - } - - public Integer getTicketNo() - { - return _ticket; - } - - public boolean isDurable() - { - return _durable; - } - - public boolean isAutoDelete() - { - return _autoDelete; - } - - // Added exchangetype in the object name lets maangement apps to do any customization required - public ObjectName getObjectName() throws MalformedObjectNameException - { - String objNameString = super.getObjectName().toString(); - objNameString = objNameString + ",ExchangeType=" + _exchangeType; - return new ObjectName(objNameString); - } + // TODO + private long _createTime = System.currentTimeMillis(); - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - } // End of MBean class + public AbstractExchange(final ExchangeType<? extends Exchange> type) + { + _type = type; + } - public AMQShortString getName() + public AMQShortString getNameShortString() { return _name; } + public final AMQShortString getTypeShortString() + { + return _type.getName(); + } + /** * Concrete exchanges must implement this method in order to create the managed representation. This is * called during initialisation (template method pattern). * @return the MBean */ - protected abstract ExchangeMBean createMBean() throws JMException; + protected abstract AbstractExchangeMBean createMBean() throws JMException; public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException @@ -173,6 +133,11 @@ public abstract class AbstractExchange implements Exchange, Managable _durable = durable; _autoDelete = autoDelete; _ticket = ticket; + + // TODO - fix + _id = getConfigStore().createId(); + + getConfigStore().addConfiguredObject(this); try { _exchangeMbean = createMBean(); @@ -185,7 +150,12 @@ public abstract class AbstractExchange implements Exchange, Managable _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation - CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getType()), String.valueOf(name), durable)); + CurrentActor.get().message(ExchangeMessages.EXH_CREATED(String.valueOf(getTypeShortString()), String.valueOf(name), durable)); + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); } public abstract Logger getLogger(); @@ -207,21 +177,32 @@ public abstract class AbstractExchange implements Exchange, Managable public void close() throws AMQException { - if (_exchangeMbean != null) - { - _exchangeMbean.unregister(); - } - if(_alternateExchange != null) + + if(_closed.compareAndSet(false,true)) { - _alternateExchange.removeReference(this); + if (_exchangeMbean != null) + { + _exchangeMbean.unregister(); + } + getConfigStore().removeConfiguredObject(this); + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } + + CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED()); + + for(Task task : _closeTaskList) + { + task.onClose(this); + } + _closeTaskList.clear(); } - - CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_DELETED()); } public String toString() { - return getClass().getSimpleName() + "[" + getName() +"]"; + return getClass().getSimpleName() + "[" + getNameShortString() +"]"; } public ManagedObject getManagedObject() @@ -288,4 +269,143 @@ public abstract class AbstractExchange implements Exchange, Managable { return !_referrers.isEmpty(); } + + public void addCloseTask(final Task task) + { + _closeTaskList.add(task); + } + + public void removeCloseTask(final Task task) + { + _closeTaskList.remove(task); + } + + public final void addBinding(final Binding binding) + { + _bindings.add(binding); + int bindingCountSize = _bindings.size(); + int maxBindingsSize; + while((maxBindingsSize = _bindingCountHigh.get()) < bindingCountSize) + { + _bindingCountHigh.compareAndSet(maxBindingsSize, bindingCountSize); + } + for(BindingListener listener : _listeners) + { + listener.bindingAdded(this, binding); + } + onBind(binding); + } + + public long getBindingCountHigh() + { + return _bindingCountHigh.get(); + } + + public final void removeBinding(final Binding binding) + { + onUnbind(binding); + for(BindingListener listener : _listeners) + { + listener.bindingRemoved(this, binding); + } + _bindings.remove(binding); + } + + public final Collection<Binding> getBindings() + { + return Collections.unmodifiableList(_bindings); + } + + protected abstract void onBind(final Binding binding); + + protected abstract void onUnbind(final Binding binding); + + + public String getName() + { + return _name.toString(); + } + + public ExchangeType getType() + { + return _type; + } + + public Map<String, Object> getArguments() + { + // TODO - Fix + return Collections.EMPTY_MAP; + } + + public UUID getId() + { + return _id; + } + + public ExchangeConfigType getConfigType() + { + return ExchangeConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _virtualHost; + } + + public long getBindingCount() + { + return getBindings().size(); + } + + + + public final ArrayList<? extends BaseQueue> route(final InboundMessage message) + { + _receivedMessageCount.incrementAndGet(); + _receivedMessageSize.addAndGet(message.getSize()); + final ArrayList<? extends BaseQueue> queues = doRoute(message); + if(queues != null && !queues.isEmpty()) + { + _routedMessageCount.incrementAndGet(); + _routedMessageSize.addAndGet(message.getSize()); + } + return queues; + } + + protected abstract ArrayList<? extends BaseQueue> doRoute(final InboundMessage message); + + public long getMsgReceives() + { + return _receivedMessageCount.get(); + } + + public long getMsgRoutes() + { + return _routedMessageCount.get(); + } + + public long getByteReceives() + { + return _receivedMessageSize.get(); + } + + public long getByteRoutes() + { + return _routedMessageSize.get(); + } + + public long getCreateTime() + { + return _createTime; + } + + public void addBindingListener(final BindingListener listener) + { + _listeners.add(listener); + } + + public void removeBindingListener(final BindingListener listener) + { + _listeners.remove(listener); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java new file mode 100644 index 0000000000..ece8bc90fe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -0,0 +1,139 @@ +/* + * + * 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.qpid.server.exchange; + +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.framing.AMQShortString; + +import javax.management.openmbean.*; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; +import javax.management.JMException; + +/** + * Abstract MBean class. This has some of the methods implemented from + * management intrerface for exchanges. Any implementaion of an + * Exchange MBean should extend this class. + */ +public abstract class AbstractExchangeMBean<T extends AbstractExchange> extends AMQManagedObject implements ManagedExchange +{ + // open mbean data types for representing exchange bindings + protected OpenType[] _bindingItemTypes; + protected CompositeType _bindingDataType; + protected TabularType _bindinglistDataType; + + + private T _exchange; + + public AbstractExchangeMBean(final T abstractExchange) throws NotCompliantMBeanException + { + super(ManagedExchange.class, ManagedExchange.TYPE); + _exchange = abstractExchange; + } + + protected void init() throws OpenDataException + { + _bindingItemTypes = new OpenType[2]; + _bindingItemTypes[0] = SimpleType.STRING; + _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", + COMPOSITE_ITEM_NAMES, COMPOSITE_ITEM_DESCRIPTIONS, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + _bindingDataType, TABULAR_UNIQUE_INDEX); + } + + public ManagedObject getParentObject() + { + return _exchange.getVirtualHost().getManagedObject(); + } + + public T getExchange() + { + return _exchange; + } + + + public String getObjectInstanceName() + { + return _exchange.getNameShortString().toString(); + } + + public String getName() + { + return _exchange.getNameShortString().toString(); + } + + public String getExchangeType() + { + return _exchange.getTypeShortString().toString(); + } + + public Integer getTicketNo() + { + return _exchange._ticket; + } + + public boolean isDurable() + { + return _exchange._durable; + } + + public boolean isAutoDelete() + { + return _exchange._autoDelete; + } + + // Added exchangetype in the object name lets maangement apps to do any customization required + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + getExchangeType(); + return new ObjectName(objNameString); + } + + protected ManagedObjectRegistry getManagedObjectRegistry() + { + return ApplicationRegistry.getInstance().getManagedObjectRegistry(); + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + VirtualHost vhost = getExchange().getVirtualHost(); + AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); + if (queue == null) + { + throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); + } + + CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); + vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); + CurrentActor.remove(); + } +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 6b0cf89b95..1c4c341c14 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -20,19 +20,20 @@ */ package org.apache.qpid.server.exchange; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.qmf.ManagementExchange; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + public class DefaultExchangeFactory implements ExchangeFactory { private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class); @@ -47,6 +48,7 @@ public class DefaultExchangeFactory implements ExchangeFactory registerExchangeType(TopicExchange.TYPE); registerExchangeType(HeadersExchange.TYPE); registerExchangeType(FanoutExchange.TYPE); + registerExchangeType(ManagementExchange.TYPE); } public void registerExchangeType(ExchangeType<? extends Exchange> type) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 7b21ad6b91..84444450c9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -66,8 +66,8 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void registerExchange(Exchange exchange) throws AMQException { - _exchangeMap.put(exchange.getName(), exchange); - _exchangeMapStr.put(exchange.getName().toString(), exchange); + _exchangeMap.put(exchange.getNameShortString(), exchange); + _exchangeMapStr.put(exchange.getNameShortString().toString(), exchange); } public void setDefaultExchange(Exchange exchange) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 3c3902c545..cb0d8ecf8f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -20,40 +20,29 @@ */ package org.apache.qpid.server.exchange; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.InboundMessage; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; + +import javax.management.JMException; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; public class DirectExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(DirectExchange.class); - /** - * Maps from queue name to queue instances - */ - private final Index _index = new Index(); + private final ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>> _bindingsByKey = + new ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>>(); public static final ExchangeType<DirectExchange> TYPE = new ExchangeType<DirectExchange>() { @@ -85,73 +74,15 @@ public class DirectExchange extends AbstractExchange } }; - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Direct Exchange") - private final class DirectExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DirectExchangeMBean() throws JMException - { - super(); - _exchangeType = "direct"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - Map<AMQShortString, List<AMQQueue>> bindings = _index.getBindingsMap(); - _bindingList = new TabularDataSupport(_bindinglistDataType); - - for (Map.Entry<AMQShortString, List<AMQQueue>> entry : bindings.entrySet()) - { - AMQShortString key = entry.getKey(); - List<String> queueList = new ArrayList<String>(); - - List<AMQQueue> queues = entry.getValue(); - for (AMQQueue q : queues) - { - queueList.add(q.getName().toString()); - } - - Object[] bindingItemValues = {key.toString(), queueList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - try - { - queue.bind(DirectExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - finally - { - CurrentActor.remove(); - } - } - - }// End of MBean class + public DirectExchange() + { + super(TYPE); + } - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { - return new DirectExchangeMBean(); + return new DirectExchangeMBean(this); } public Logger getLogger() @@ -159,68 +90,36 @@ public class DirectExchange extends AbstractExchange return _logger; } - public AMQShortString getType() - { - return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; - } - public void registerQueue(String routingKey, AMQQueue queue, Map<String,Object> args) throws AMQException + public ArrayList<? extends BaseQueue> doRoute(InboundMessage payload) { - registerQueue(new AMQShortString(routingKey), queue); - } - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - registerQueue(routingKey, queue); - } + final String routingKey = payload.getRoutingKey(); - private void registerQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException - { - assert queue != null; - assert routingKey != null; - if (!_index.add(routingKey, queue)) + CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(routingKey == null ? "" : routingKey); + + if(bindings != null) { - if (_logger.isDebugEnabled()) + final ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(bindings.size()); + + for(Binding binding : bindings) { - _logger.debug("Queue (" + queue + ") is already registered with routing key " + routingKey); + queues.add(binding.getQueue()); + binding.incrementMatches(); } - } - else - { + if (_logger.isDebugEnabled()) { - _logger.debug("Binding queue:" + queue + " with routing key '" + routingKey +"' to exchange:" + this); + _logger.debug("Publishing message to queue " + queues); } - } - } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert routingKey != null; - - if (!_index.remove(routingKey, queue)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + - " with routing key " + routingKey + ". No queue was registered with that _routing key"); + return queues; } - } - - public ArrayList<AMQQueue> route(InboundMessage payload) - { - - final String routingKey = payload.getRoutingKey(); - - - final ArrayList<AMQQueue> queues = (routingKey == null) ? _index.get("") : _index.get(routingKey); - - if (_logger.isDebugEnabled()) + else { - _logger.debug("Publishing message to queue " + queues); + return new ArrayList<BaseQueue>(0); } - return queues; - } @@ -232,24 +131,40 @@ public class DirectExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, AMQQueue queue) { - final List<AMQQueue> queues = _index.get(routingKey); - return queues != null && queues.contains(queue); + String bindingKey = (routingKey == null) ? "" : routingKey.toString(); + CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey); + if(bindings != null) + { + for(Binding binding : bindings) + { + if(binding.getQueue().equals(queue)) + { + return true; + } + } + } + return false; + } public boolean isBound(AMQShortString routingKey) { - final List<AMQQueue> queues = _index.get(routingKey); - return queues != null && !queues.isEmpty(); + String bindingKey = (routingKey == null) ? "" : routingKey.toString(); + CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey); + return bindings != null && !bindings.isEmpty(); } public boolean isBound(AMQQueue queue) { - Map<AMQShortString, List<AMQQueue>> bindings = _index.getBindingsMap(); - for (List<AMQQueue> queues : bindings.values()) + + for (CopyOnWriteArraySet<Binding> bindings : _bindingsByKey.values()) { - if (queues.contains(queue)) + for(Binding binding : bindings) { - return true; + if(binding.getQueue().equals(queue)) + { + return true; + } } } return false; @@ -257,11 +172,45 @@ public class DirectExchange extends AbstractExchange public boolean hasBindings() { - return !_index.getBindingsMap().isEmpty(); + return !getBindings().isEmpty(); } - public Map<AMQShortString, List<AMQQueue>> getBindings() + protected void onBind(final Binding binding) { - return _index.getBindingsMap(); + String bindingKey = binding.getBindingKey(); + AMQQueue queue = binding.getQueue(); + AMQShortString routingKey = AMQShortString.valueOf(bindingKey); + + assert queue != null; + assert routingKey != null; + + CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey); + + if(bindings == null) + { + bindings = new CopyOnWriteArraySet<Binding>(); + CopyOnWriteArraySet<Binding> newBindings; + if((newBindings = _bindingsByKey.putIfAbsent(bindingKey, bindings)) != null) + { + bindings = newBindings; + } + } + + bindings.add(binding); + + } + + protected void onUnbind(final Binding binding) + { + assert binding != null; + + CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(binding.getBindingKey()); + if(bindings != null) + { + bindings.remove(binding); + } + } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java new file mode 100644 index 0000000000..086832c045 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java @@ -0,0 +1,79 @@ +/* + * + * 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.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * MBean class implementing the management interfaces. + */ +@MBeanDescription("Management Bean for Direct Exchange") +final class DirectExchangeMBean extends AbstractExchangeMBean<DirectExchange> +{ + @MBeanConstructor("Creates an MBean for AMQ direct exchange") + public DirectExchangeMBean(final DirectExchange exchange) throws JMException + { + super(exchange); + + init(); + } + + public TabularData bindings() throws OpenDataException + { + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + + Map<String, List<String>> bindingMap = new HashMap<String, List<String>>(); + + for (Binding binding : getExchange().getBindings()) + { + String key = binding.getBindingKey(); + List<String> queueList = bindingMap.get(key); + if(queueList == null) + { + queueList = new ArrayList<String>(); + bindingMap.put(key, queueList); + } + queueList.add(binding.getQueue().getNameShortString().toString()); + + } + + for(Map.Entry<String, List<String>> entry : bindingMap.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingData); + } + + return bindingList; + } + + + +}// End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 4bbdeaef1c..8a31b1bab1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -25,17 +25,31 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.binding.BindingFactory; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ExchangeConfig; import javax.management.JMException; import java.util.ArrayList; +import java.util.List; +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArrayList; -public interface Exchange extends ExchangeReferrer +public interface Exchange extends ExchangeReferrer, ExchangeConfig { - AMQShortString getName(); - AMQShortString getType(); + public interface BindingListener + { + void bindingAdded(Exchange exchange, Binding binding); + void bindingRemoved(Exchange exchange, Binding binding); + } + + AMQShortString getNameShortString(); + + AMQShortString getTypeShortString(); void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException, JMException; @@ -51,13 +65,8 @@ public interface Exchange extends ExchangeReferrer void close() throws AMQException; - void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - - void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - ArrayList<AMQQueue> route(InboundMessage message); + ArrayList<? extends BaseQueue> route(InboundMessage message); /** @@ -101,6 +110,11 @@ public interface Exchange extends ExchangeReferrer boolean isBound(String bindingKey); + void addCloseTask(Task task); + + void removeCloseTask(Task task); + + Exchange getAlternateExchange(); void setAlternateExchange(Exchange exchange); @@ -110,4 +124,20 @@ public interface Exchange extends ExchangeReferrer void addReference(ExchangeReferrer exchange); boolean hasReferrers(); + + void addBinding(Binding binding); + + void removeBinding(Binding binding); + + Collection<Binding> getBindings(); + + public void addBindingListener(BindingListener listener); + + public void removeBindingListener(BindingListener listener); + + + public static interface Task + { + public void onClose(Exchange exchange); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 00f8ebd856..bd75f7bc51 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -21,109 +21,35 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.InboundMessage; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.List; -import java.util.Map; import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ConcurrentHashMap; public class FanoutExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(FanoutExchange.class); + private static final Integer ONE = Integer.valueOf(1); + /** * Maps from queue name to queue instances */ - private final CopyOnWriteArraySet<AMQQueue> _queues = new CopyOnWriteArraySet<AMQQueue>(); + private final ConcurrentHashMap<AMQQueue,Integer> _queues = new ConcurrentHashMap<AMQQueue,Integer>(); - /** - * MBean class implementing the management interfaces. - */ - @MBeanDescription("Management Bean for Fanout Exchange") - private final class FanoutExchangeMBean extends ExchangeMBean + protected AbstractExchangeMBean createMBean() throws JMException { - private static final String BINDING_KEY_SUBSTITUTE = "*"; - - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean() throws JMException - { - super(); - _exchangeType = "fanout"; - init(); - } - - public TabularData bindings() throws OpenDataException - { - - _bindingList = new TabularDataSupport(_bindinglistDataType); - - if(_queues.isEmpty()) - { - return _bindingList; - } - - ArrayList<String> queueNames = new ArrayList<String>(); - - for (AMQQueue queue : _queues) - { - String queueName = queue.getName().toString(); - queueNames.add(queueName); - } - - Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); - - return _bindingList; - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - try - { - queue.bind(FanoutExchange.this, new AMQShortString(BINDING_KEY_SUBSTITUTE), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - finally - { - CurrentActor.remove(); - } - } - - } // End of MBean class - - protected ExchangeMBean createMBean() throws JMException - { - return new FanoutExchange.FanoutExchangeMBean(); + return new FanoutExchangeMBean(this); } public Logger getLogger() @@ -161,51 +87,26 @@ public class FanoutExchange extends AbstractExchange } }; - public Map<AMQShortString, List<AMQQueue>> getBindings() + public FanoutExchange() { - return null; + super(TYPE); } - public AMQShortString getType() + public ArrayList<BaseQueue> doRoute(InboundMessage payload) { - return ExchangeDefaults.FANOUT_EXCHANGE_CLASS; - } - - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - if (_queues.contains(queue)) - { - _logger.debug("Queue " + queue + " is already registered"); - } - else - { - _queues.add(queue); - _logger.debug("Binding queue " + queue + " with routing key " + routingKey + " to exchange " + this); - } - } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - - if (!_queues.remove(queue)) + if (_logger.isDebugEnabled()) { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() + ". "); + _logger.debug("Publishing message to queue " + _queues); } - } - public ArrayList<AMQQueue> route(InboundMessage payload) - { - - - if (_logger.isDebugEnabled()) + for(Binding b : getBindings()) { - _logger.debug("Publishing message to queue " + _queues); + b.incrementMatches(); } - return new ArrayList(_queues); + return new ArrayList<BaseQueue>(_queues.keySet()); } @@ -235,4 +136,71 @@ public class FanoutExchange extends AbstractExchange { return !_queues.isEmpty(); } + + protected void onBind(final Binding binding) + { + AMQQueue queue = binding.getQueue(); + assert queue != null; + + Integer oldVal; + + if((oldVal = _queues.putIfAbsent(queue, ONE)) != null) + { + Integer newVal = oldVal+1; + while(!_queues.replace(queue, oldVal, newVal)) + { + oldVal = _queues.get(queue); + if(oldVal == null) + { + oldVal = _queues.putIfAbsent(queue, ONE); + if(oldVal == null) + { + break; + } + } + newVal = oldVal + 1; + } + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Binding queue " + queue + + " with routing key " + new AMQShortString(binding.getBindingKey()) + " to exchange " + this); + } + } + + protected void onUnbind(final Binding binding) + { + AMQQueue queue = binding.getQueue(); + Integer oldValue = _queues.get(queue); + + boolean done = false; + + while(!(done || oldValue == null)) + { + while(!(done || oldValue == null) && oldValue.intValue() == 1) + { + if(!_queues.remove(queue, oldValue)) + { + oldValue = _queues.get(queue); + } + else + { + done = true; + } + } + while(!(done || oldValue == null) && oldValue.intValue() != 1) + { + Integer newValue = oldValue - 1; + if(!_queues.replace(queue, oldValue, newValue)) + { + oldValue = _queues.get(queue); + } + else + { + done = true; + } + } + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java new file mode 100644 index 0000000000..d5734f76a5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java @@ -0,0 +1,68 @@ +/* + * + * 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.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.ArrayList; + +/** + * MBean class implementing the management interfaces. + */ +@MBeanDescription("Management Bean for Fanout Exchange") +final class FanoutExchangeMBean extends AbstractExchangeMBean<FanoutExchange> +{ + private static final String BINDING_KEY_SUBSTITUTE = "*"; + + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") + public FanoutExchangeMBean(final FanoutExchange exchange) throws JMException + { + super(exchange); + init(); + } + + public TabularData bindings() throws OpenDataException + { + + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + + + ArrayList<String> queueNames = new ArrayList<String>(); + + for (Binding binding : getExchange().getBindings()) + { + String queueName = binding.getQueue().getNameShortString().toString(); + queueNames.add(queueName); + } + + Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingData); + + return bindingList; + } + + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 5677cc4510..ce0b14932f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -22,33 +22,20 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.binding.Binding; import javax.management.JMException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; @@ -119,151 +106,40 @@ public class HeadersExchange extends AbstractExchange private final List<Registration> _bindings = new CopyOnWriteArrayList<Registration>(); private Map<AMQShortString, Registration> _bindingByKey = new ConcurrentHashMap<AMQShortString, Registration>(); - /** - * HeadersExchangeMBean class implements the management interface for the - * Header Exchanges. - */ - @MBeanDescription("Management Bean for Headers Exchange") - private final class HeadersExchangeMBean extends ExchangeMBean - { - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean() throws JMException - { - super(); - _exchangeType = "headers"; - init(); - } - - /** - * initialises the OpenType objects. - */ - protected void init() throws OpenDataException - { - - _bindingItemTypes = new OpenType[3]; - _bindingItemTypes[0] = SimpleType.INTEGER; - _bindingItemTypes[1] = SimpleType.STRING; - _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", - HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX); - } - - public TabularData bindings() throws OpenDataException - { - _bindingList = new TabularDataSupport(_bindinglistDataType); - int count = 1; - for (Iterator<Registration> itr = _bindings.iterator(); itr.hasNext();) - { - Registration registration = itr.next(); - String queueName = registration.queue.getName().toString(); - - HeadersBinding headers = registration.binding; - FieldTable headerMappings = headers.getMappings(); - final List<String> mappingList = new ArrayList<String>(); - - headerMappings.processOverElements(new FieldTable.FieldTableElementProcessor() - { - - public boolean processElement(String propertyName, AMQTypedValue value) - { - mappingList.add(propertyName + "=" + value.getValue()); - return true; - } - - public Object getResult() - { - return mappingList; - } - }); - - Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingData); - } - - return _bindingList; - } - - /** - * Creates bindings. Binding pattern is as follows- - * <attributename>=<value>,<attributename>=<value>,... - * @param queueName - * @param binding - * @throws javax.management.JMException - */ - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - String[] bindings = binding.split(","); - FieldTable bindingMap = new FieldTable(); - for (int i = 0; i < bindings.length; i++) - { - String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2) - { - throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" "); - } - - if(keyAndValue.length ==1) - { - //no value was given, only a key. Use an empty value - //to signal match on key presence alone - bindingMap.setString(keyAndValue[0], ""); - } - else - { - bindingMap.setString(keyAndValue[0], keyAndValue[1]); - } - } - - _bindings.add(new Registration(new HeadersBinding(bindingMap), queue, new AMQShortString(binding))); - } - - } // End of MBean class + public HeadersExchange() + { + super(TYPE); + } - public AMQShortString getType() + public void registerQueue(String routingKey, AMQQueue queue, Map<String,Object> args) { - return ExchangeDefaults.HEADERS_EXCHANGE_CLASS; + registerQueue(new AMQShortString(routingKey), queue, FieldTable.convertToFieldTable(args)); } - public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) { - _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); + _logger.debug("Exchange " + getNameShortString() + ": Binding " + queue.getNameShortString() + " with " + args); Registration registration = new Registration(new HeadersBinding(args), queue, routingKey); _bindings.add(registration); } - public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + public void deregisterQueue(String routingKey, AMQQueue queue, Map<String,Object> args) { - _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - - if(!_bindings.remove(new Registration(args == null ? null : new HeadersBinding(args), queue, routingKey))) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with headers args " + args); - } + _bindings.remove(new Registration(args == null ? null : new HeadersBinding(FieldTable.convertToFieldTable(args)), queue, new AMQShortString(routingKey))); } - public ArrayList<AMQQueue> route(InboundMessage payload) + public ArrayList<BaseQueue> doRoute(InboundMessage payload) { AMQMessageHeader header = payload.getMessageHeader(); if (_logger.isDebugEnabled()) { - _logger.debug("Exchange " + getName() + ": routing message with headers " + header); + _logger.debug("Exchange " + getNameShortString() + ": routing message with headers " + header); } boolean routed = false; - ArrayList<AMQQueue> queues = new ArrayList<AMQQueue>(); + ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(); for (Registration e : _bindings) { @@ -271,8 +147,8 @@ public class HeadersExchange extends AbstractExchange { if (_logger.isDebugEnabled()) { - _logger.debug("Exchange " + getName() + ": delivering message with headers " + - header + " to " + e.queue.getName()); + _logger.debug("Exchange " + getNameShortString() + ": delivering message with headers " + + header + " to " + e.queue.getNameShortString()); } queues.add(e.queue); @@ -315,6 +191,8 @@ public class HeadersExchange extends AbstractExchange return !_bindings.isEmpty(); } + + protected FieldTable getHeaders(ContentHeaderBody contentHeaderFrame) { //what if the content type is not 'basic'? 'file' and 'stream' content classes also define headers, @@ -322,14 +200,9 @@ public class HeadersExchange extends AbstractExchange return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders(); } - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { - return new HeadersExchangeMBean(); - } - - public Map<AMQShortString, List<AMQQueue>> getBindings() - { - return null; + return new HeadersExchangeMBean(this); } public Logger getLogger() @@ -338,7 +211,7 @@ public class HeadersExchange extends AbstractExchange } - private static class Registration + static class Registration { private final HeadersBinding binding; private final AMQQueue queue; @@ -365,5 +238,31 @@ public class HeadersExchange extends AbstractExchange && (routingKey == null ? ((Registration)o).routingKey == null : routingKey.equals(((Registration)o).routingKey)); } + + public HeadersBinding getBinding() + { + return binding; + } + + public AMQQueue getQueue() + { + return queue; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } } + + protected void onBind(final Binding binding) + { + registerQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments()); + } + + protected void onUnbind(final Binding binding) + { + deregisterQueue(binding.getBindingKey(), binding.getQueue(), binding.getArguments()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java new file mode 100644 index 0000000000..2c7985b480 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java @@ -0,0 +1,96 @@ +/* + * + * 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.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; + +/** + * HeadersExchangeMBean class implements the management interface for the + * Header Exchanges. + */ +@MBeanDescription("Management Bean for Headers Exchange") +final class HeadersExchangeMBean extends AbstractExchangeMBean<HeadersExchange> +{ + + @MBeanConstructor("Creates an MBean for AMQ Headers exchange") + public HeadersExchangeMBean(final HeadersExchange headersExchange) throws JMException + { + super(headersExchange); + init(); + } + + /** + * initialises the OpenType objects. + */ + protected void init() throws OpenDataException + { + + _bindingItemTypes = new OpenType[3]; + _bindingItemTypes[0] = SimpleType.INTEGER; + _bindingItemTypes[1] = SimpleType.STRING; + _bindingItemTypes[2] = new ArrayType(1, SimpleType.STRING); + _bindingDataType = new CompositeType("Exchange Binding", "Queue name and header bindings", + HEADERS_COMPOSITE_ITEM_NAMES, HEADERS_COMPOSITE_ITEM_DESC, _bindingItemTypes); + _bindinglistDataType = new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), + _bindingDataType, HEADERS_TABULAR_UNIQUE_INDEX); + } + + public TabularData bindings() throws OpenDataException + { + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + int count = 1; + for (Binding binding : getExchange().getBindings()) + { + + String queueName = binding.getQueue().getNameShortString().toString(); + + + Map<String,Object> headerMappings = binding.getArguments(); + final List<String> mappingList = new ArrayList<String>(); + + if(headerMappings != null) + { + for(Map.Entry<String,Object> entry : headerMappings.entrySet()) + { + + mappingList.add(entry.getKey() + "=" + entry.getValue()); + } + } + + + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(_bindingDataType, HEADERS_COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingData); + } + + return bindingList; + } + + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java deleted file mode 100644 index 90d04c814a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * - * 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.qpid.server.exchange; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.AMQQueue; - -/** - * An index of queues against routing key. Allows multiple queues to be stored - * against the same key. Used in the DirectExchange. - */ -class Index -{ - private ConcurrentMap<AMQShortString, ArrayList<AMQQueue>> _index - = new ConcurrentHashMap<AMQShortString, ArrayList<AMQQueue>>(); - private ConcurrentMap<String, ArrayList<AMQQueue>> _stringIndex - = new ConcurrentHashMap<String, ArrayList<AMQQueue>>(); - - - synchronized boolean add(AMQShortString key, AMQQueue queue) - { - ArrayList<AMQQueue> queues = _index.get(key); - if(queues == null) - { - queues = new ArrayList<AMQQueue>(); - } - else - { - queues = new ArrayList<AMQQueue>(queues); - } - - //next call is atomic, so there is no race to create the list - _index.put(key, queues); - _stringIndex.put(key.toString(), queues); - - if(queues.contains(queue)) - { - return false; - } - else - { - return queues.add(queue); - } - } - - - - synchronized boolean remove(AMQShortString key, AMQQueue queue) - { - ArrayList<AMQQueue> queues = _index.get(key); - if (queues != null) - { - queues = new ArrayList<AMQQueue>(queues); - boolean removed = queues.remove(queue); - if(removed) - { - if (queues.size() == 0) - { - _index.remove(key); - _stringIndex.remove(key.toString()); - } - else - { - _index.put(key, queues); - _stringIndex.put(key.toString(), queues); - } - } - return removed; - } - return false; - } - - ArrayList<AMQQueue> get(AMQShortString key) - { - return _index.get(key); - } - - ArrayList<AMQQueue> get(String key) - { - return _stringIndex.get(key); - } - - - Map<AMQShortString, List<AMQQueue>> getBindingsMap() - { - return new HashMap<AMQShortString, List<AMQQueue>>(_index); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index d5ca5a8a81..14f15dd92c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -21,32 +21,21 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQShortStringTokenizer; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.topic.TopicParser; -import org.apache.qpid.server.exchange.topic.TopicMatcherResult; -import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.exchange.topic.*; import org.apache.qpid.server.filter.JMSSelectorFilter; import org.apache.qpid.server.message.InboundMessage; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.lang.ref.WeakReference; @@ -87,314 +76,45 @@ public class TopicExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(TopicExchange.class); -/* - private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _bindingKey2queues = - new ConcurrentHashMap<AMQShortString, List<AMQQueue>>(); - private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _simpleBindingKey2queues = - new ConcurrentHashMap<AMQShortString, List<AMQQueue>>(); - private final ConcurrentHashMap<AMQShortString, List<AMQQueue>> _wildCardBindingKey2queues = - new ConcurrentHashMap<AMQShortString, List<AMQQueue>>(); -*/ - // private ConcurrentHashMap<AMQShortString, AMQQueue> _routingKey2queue = new ConcurrentHashMap<AMQShortString, AMQQueue>(); - private static final byte TOPIC_SEPARATOR = (byte)'.'; - private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); - private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); - private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); - - private static final byte HASH_BYTE = (byte)'#'; - private static final byte STAR_BYTE = (byte)'*'; + private final TopicParser _parser = new TopicParser(); private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults = new ConcurrentHashMap<AMQShortString, TopicExchangeResult>(); - private final Map<Binding, FieldTable> _bindings = new HashMap<Binding, FieldTable>(); + private final Map<TopicBinding, FieldTable> _bindings = new HashMap<TopicBinding, FieldTable>(); private final Map<String, WeakReference<JMSSelectorFilter>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter>>(); - public static class Binding + public TopicExchange() { - private final AMQShortString _bindingKey; - private final AMQQueue _queue; - private final FieldTable _args; - - public Binding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) - { - _bindingKey = bindingKey; - _queue = queue; - _args = args; - } - - public AMQShortString getBindingKey() - { - return _bindingKey; - } - - public AMQQueue getQueue() - { - return _queue; - } - - public int hashCode() - { - return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); - } - - public boolean equals(Object o) - { - if(this == o) - { - return true; - } - if(o instanceof Binding) - { - Binding other = (Binding) o; - return (_queue == other._queue) - && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); - } - return false; - } - } - - - - private final class TopicExchangeResult implements TopicMatcherResult - { - private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>(); - private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>(); - - public void addUnfilteredQueue(AMQQueue queue) - { - Integer instances = _unfilteredQueues.get(queue); - if(instances == null) - { - _unfilteredQueues.put(queue, 1); - } - else - { - _unfilteredQueues.put(queue, instances + 1); - } - } - - public void removeUnfilteredQueue(AMQQueue queue) - { - Integer instances = _unfilteredQueues.get(queue); - if(instances == 1) - { - _unfilteredQueues.remove(queue); - } - else - { - _unfilteredQueues.put(queue,instances - 1); - } - - } - - - public void addFilteredQueue(AMQQueue queue, MessageFilter filter) - { - Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); - if(filters == null) - { - filters = new ConcurrentHashMap<MessageFilter,Integer>(); - _filteredQueues.put(queue, filters); - } - Integer instances = filters.get(filter); - if(instances == null) - { - filters.put(filter,1); - } - else - { - filters.put(filter, instances + 1); - } - - } - - public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) - { - Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); - if(filters != null) - { - Integer instances = filters.get(filter); - if(instances != null) - { - if(instances == 1) - { - filters.remove(filter); - if(filters.isEmpty()) - { - _filteredQueues.remove(queue); - } - } - else - { - filters.put(filter, instances - 1); - } - } - - } - - } - - public void replaceQueueFilter(AMQQueue queue, - MessageFilter oldFilter, - MessageFilter newFilter) - { - Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); - Map<MessageFilter,Integer> newFilters = new ConcurrentHashMap<MessageFilter,Integer>(filters); - Integer oldFilterInstances = filters.get(oldFilter); - if(oldFilterInstances == 1) - { - newFilters.remove(oldFilter); - } - else - { - newFilters.put(oldFilter, oldFilterInstances-1); - } - Integer newFilterInstances = filters.get(newFilter); - if(newFilterInstances == null) - { - newFilters.put(newFilter, 1); - } - else - { - newFilters.put(newFilter, newFilterInstances+1); - } - _filteredQueues.put(queue,newFilters); - } - - public Collection<AMQQueue> processMessage(InboundMessage msg, Collection<AMQQueue> queues) - { - if(queues == null) - { - if(_filteredQueues.isEmpty()) - { - return new ArrayList<AMQQueue>(_unfilteredQueues.keySet()); - } - else - { - queues = new HashSet<AMQQueue>(); - } - } - else if(!(queues instanceof Set)) - { - queues = new HashSet<AMQQueue>(queues); - } - - queues.addAll(_unfilteredQueues.keySet()); - if(!_filteredQueues.isEmpty()) - { - for(Map.Entry<AMQQueue, Map<MessageFilter, Integer>> entry : _filteredQueues.entrySet()) - { - if(!queues.contains(entry.getKey())) - { - for(MessageFilter filter : entry.getValue().keySet()) - { - if(filter.matches(msg)) - { - queues.add(entry.getKey()); - } - } - } - } - } - return queues; - } - + super(TYPE); } - - /** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ - @MBeanDescription("Management Bean for Topic Exchange") - private final class TopicExchangeMBean extends ExchangeMBean + public synchronized void registerQueue(String rKey, AMQQueue queue, Map<String,Object> args) { - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public TopicExchangeMBean() throws JMException + try { - super(); - _exchangeType = "topic"; - init(); + registerQueue(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args)); } - - /** returns exchange bindings in tabular form */ - public TabularData bindings() throws OpenDataException + catch (AMQInvalidArgumentException e) { - _bindingList = new TabularDataSupport(_bindinglistDataType); - Map<String, List<String>> bindingData = new HashMap<String, List<String>>(); - for (Binding binding : _bindings.keySet()) - { - String key = binding.getBindingKey().toString(); - List<String> queueNames = bindingData.get(key); - if(queueNames == null) - { - queueNames = new ArrayList<String>(); - bindingData.put(key, queueNames); - } - queueNames.add(binding.getQueue().getName().toString()); - - } - for(Map.Entry<String, List<String>> entry : bindingData.entrySet()) - { - Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; - CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); - _bindingList.put(bindingCompositeData); - } - - return _bindingList; + throw new RuntimeException(e); } - - public void createNewBinding(String queueName, String binding) throws JMException - { - AMQQueue queue = getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the exchange."); - } - - CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - try - { - queue.bind(TopicExchange.this, new AMQShortString(binding), null); - } - catch (AMQException ex) - { - throw new MBeanException(ex); - } - finally - { - CurrentActor.remove(); - } - } - - } // End of MBean class - - public AMQShortString getType() - { - return ExchangeDefaults.TOPIC_EXCHANGE_CLASS; } - public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException + public synchronized void registerQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQInvalidArgumentException { assert queue != null; assert rKey != null; - _logger.debug("Registering queue " + queue.getName() + " with routing key " + rKey); + _logger.debug("Registering queue " + queue.getNameShortString() + " with routing key " + rKey); - AMQShortString routingKey; + AMQShortString routingKey = TopicNormalizer.normalize(rKey); - if(rKey.contains(HASH_BYTE) || rKey.contains(STAR_BYTE)) - { - routingKey = normalize(rKey); - } - else - { - routingKey = rKey; - } - - Binding binding = new Binding(rKey, queue, args); + TopicBinding binding = new TopicBinding(rKey, queue, args); if(_bindings.containsKey(binding)) { @@ -463,8 +183,7 @@ public class TopicExchange extends AbstractExchange } - private JMSSelectorFilter createSelectorFilter(final FieldTable args) - throws AMQException + private JMSSelectorFilter createSelectorFilter(final FieldTable args) throws AMQInvalidArgumentException { final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); @@ -484,58 +203,7 @@ public class TopicExchange extends AbstractExchange return args != null && args.containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()) && args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()).trim().length() != 0; } - private AMQShortString normalize(AMQShortString routingKey) - { - if(routingKey == null) - { - routingKey = AMQShortString.EMPTY_STRING; - } - - AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); - - List<AMQShortString> subscriptionList = new ArrayList<AMQShortString>(); - - while (routingTokens.hasMoreTokens()) - { - subscriptionList.add(routingTokens.nextToken()); - } - - int size = subscriptionList.size(); - - for (int index = 0; index < size; index++) - { - // if there are more levels - if ((index + 1) < size) - { - if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) - { - if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) - { - // we don't need #.# delete this one - subscriptionList.remove(index); - size--; - // redo this normalisation - index--; - } - - if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) - { - // we don't want #.* swap to *.# - // remove it and put it in at index + 1 - subscriptionList.add(index + 1, subscriptionList.remove(index)); - } - } - } // if we have more levels - } - - - - AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); - - return normalizedString; - } - - public ArrayList<AMQQueue> route(InboundMessage payload) + public ArrayList<BaseQueue> doRoute(InboundMessage payload) { final AMQShortString routingKey = payload.getRoutingKey() == null @@ -544,7 +212,7 @@ public class TopicExchange extends AbstractExchange // The copy here is unfortunate, but not too bad relevant to the amount of // things created and copied in getMatchedQueues - ArrayList<AMQQueue> queues = new ArrayList<AMQQueue>(); + ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(); queues.addAll(getMatchedQueues(payload, routingKey)); if(queues == null || queues.isEmpty()) @@ -558,7 +226,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) { - Binding binding = new Binding(routingKey, queue, arguments); + TopicBinding binding = new TopicBinding(routingKey, queue, arguments); if (arguments == null) { return _bindings.containsKey(binding); @@ -585,7 +253,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey) { - for(Binding b : _bindings.keySet()) + for(TopicBinding b : _bindings.keySet()) { if(b.getBindingKey().equals(routingKey)) { @@ -598,7 +266,7 @@ public class TopicExchange extends AbstractExchange public boolean isBound(AMQQueue queue) { - for(Binding b : _bindings.keySet()) + for(TopicBinding b : _bindings.keySet()) { if(b.getQueue().equals(queue)) { @@ -614,37 +282,45 @@ public class TopicExchange extends AbstractExchange return !_bindings.isEmpty(); } - public synchronized void deregisterQueue(AMQShortString rKey, AMQQueue queue, FieldTable args) throws AMQException - { - assert queue != null; - assert rKey != null; - - Binding binding = new Binding(rKey, queue, args); - - if (!_bindings.containsKey(binding)) - { - throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue.getName() + " was not registered with exchange " + this.getName() - + " with routing key " + rKey + "."); - } + public void deregisterQueue(String rKey, AMQQueue queue, Map<String, Object> args) + { + removeBinding(new TopicBinding(new AMQShortString(rKey), queue, FieldTable.convertToFieldTable(args))); + } - FieldTable bindingArgs = _bindings.remove(binding); - AMQShortString bindingKey = normalize(rKey); - TopicExchangeResult result = _topicExchangeResults.get(bindingKey); - if(argumentsContainSelector(bindingArgs)) + private boolean removeBinding(final TopicBinding binding) + { + if(_bindings.containsKey(binding)) { - result.removeFilteredQueue(queue, createSelectorFilter(bindingArgs)); + FieldTable bindingArgs = _bindings.remove(binding); + AMQShortString bindingKey = TopicNormalizer.normalize(binding.getBindingKey()); + TopicExchangeResult result = _topicExchangeResults.get(bindingKey); + if(argumentsContainSelector(bindingArgs)) + { + try + { + result.removeFilteredQueue(binding.getQueue(), createSelectorFilter(bindingArgs)); + } + catch (AMQInvalidArgumentException e) + { + return false; + } + } + else + { + result.removeUnfilteredQueue(binding.getQueue()); + } + return true; } else { - result.removeUnfilteredQueue(queue); + return false; } - } - protected ExchangeMBean createMBean() throws JMException + protected AbstractExchangeMBean createMBean() throws JMException { - return new TopicExchangeMBean(); + return new TopicExchangeMBean(this); } public Logger getLogger() @@ -673,4 +349,15 @@ public class TopicExchange extends AbstractExchange } + + protected void onBind(final org.apache.qpid.server.binding.Binding binding) + { + registerQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments()); + } + + protected void onUnbind(final org.apache.qpid.server.binding.Binding binding) + { + deregisterQueue(binding.getBindingKey(),binding.getQueue(),binding.getArguments()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java new file mode 100644 index 0000000000..de39822ff7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java @@ -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.qpid.server.exchange; + +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.server.binding.Binding; + +import javax.management.JMException; +import javax.management.openmbean.*; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; + +/** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ +@MBeanDescription("Management Bean for Topic Exchange") +final class TopicExchangeMBean extends AbstractExchangeMBean<TopicExchange> +{ + private TopicExchange _topicExchange; + + @MBeanConstructor("Creates an MBean for AMQ topic exchange") + public TopicExchangeMBean(final TopicExchange topicExchange) throws JMException + { + super(topicExchange); + init(); + } + + /** returns exchange bindings in tabular form */ + public TabularData bindings() throws OpenDataException + { + TabularDataSupport bindingList = new TabularDataSupport(_bindinglistDataType); + Map<String, List<String>> bindingData = new HashMap<String, List<String>>(); + for (Binding binding : getExchange().getBindings()) + { + String key = binding.getBindingKey(); + List<String> queueNames = bindingData.get(key); + if(queueNames == null) + { + queueNames = new ArrayList<String>(); + bindingData.put(key, queueNames); + } + queueNames.add(binding.getQueue().getNameShortString().toString()); + + } + for(Map.Entry<String, List<String>> entry : bindingData.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; + CompositeData bindingCompositeData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); + bindingList.put(bindingCompositeData); + } + + return bindingList; + } + +} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java new file mode 100644 index 0000000000..c6383a886e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicBinding.java @@ -0,0 +1,70 @@ +/* + * + * 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.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.exchange.TopicExchange; + +public class TopicBinding +{ + private final AMQShortString _bindingKey; + private final AMQQueue _queue; + private final FieldTable _args; + + public TopicBinding(AMQShortString bindingKey, AMQQueue queue, FieldTable args) + { + _bindingKey = bindingKey; + _queue = queue; + _args = args; + } + + public AMQShortString getBindingKey() + { + return _bindingKey; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public int hashCode() + { + return (_bindingKey == null ? 1 : _bindingKey.hashCode())*31 +_queue.hashCode(); + } + + public boolean equals(Object o) + { + if(this == o) + { + return true; + } + if(o instanceof TopicBinding) + { + TopicBinding other = (TopicBinding) o; + return (_queue == other._queue) + && ((_bindingKey == null) ? other._bindingKey == null : _bindingKey.equals(other._bindingKey)); + } + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java new file mode 100644 index 0000000000..d9a779802f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java @@ -0,0 +1,179 @@ +/* + * + * 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.qpid.server.exchange.topic; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.filter.MessageFilter; +import org.apache.qpid.server.message.InboundMessage; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public final class TopicExchangeResult implements TopicMatcherResult +{ + private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>(); + private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>(); + + public void addUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == null) + { + _unfilteredQueues.put(queue, 1); + } + else + { + _unfilteredQueues.put(queue, instances + 1); + } + } + + public void removeUnfilteredQueue(AMQQueue queue) + { + Integer instances = _unfilteredQueues.get(queue); + if(instances == 1) + { + _unfilteredQueues.remove(queue); + } + else + { + _unfilteredQueues.put(queue,instances - 1); + } + + } + + public Collection<AMQQueue> getUnfilteredQueues() + { + return _unfilteredQueues.keySet(); + } + + + public void addFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); + if(filters == null) + { + filters = new ConcurrentHashMap<MessageFilter,Integer>(); + _filteredQueues.put(queue, filters); + } + Integer instances = filters.get(filter); + if(instances == null) + { + filters.put(filter,1); + } + else + { + filters.put(filter, instances + 1); + } + + } + + public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) + { + Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); + if(filters != null) + { + Integer instances = filters.get(filter); + if(instances != null) + { + if(instances == 1) + { + filters.remove(filter); + if(filters.isEmpty()) + { + _filteredQueues.remove(queue); + } + } + else + { + filters.put(filter, instances - 1); + } + } + + } + + } + + public void replaceQueueFilter(AMQQueue queue, + MessageFilter oldFilter, + MessageFilter newFilter) + { + Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); + Map<MessageFilter,Integer> newFilters = new ConcurrentHashMap<MessageFilter,Integer>(filters); + Integer oldFilterInstances = filters.get(oldFilter); + if(oldFilterInstances == 1) + { + newFilters.remove(oldFilter); + } + else + { + newFilters.put(oldFilter, oldFilterInstances-1); + } + Integer newFilterInstances = filters.get(newFilter); + if(newFilterInstances == null) + { + newFilters.put(newFilter, 1); + } + else + { + newFilters.put(newFilter, newFilterInstances+1); + } + _filteredQueues.put(queue,newFilters); + } + + public Collection<AMQQueue> processMessage(InboundMessage msg, Collection<AMQQueue> queues) + { + if(queues == null) + { + if(_filteredQueues.isEmpty()) + { + return new ArrayList<AMQQueue>(_unfilteredQueues.keySet()); + } + else + { + queues = new HashSet<AMQQueue>(); + } + } + else if(!(queues instanceof Set)) + { + queues = new HashSet<AMQQueue>(queues); + } + + queues.addAll(_unfilteredQueues.keySet()); + if(!_filteredQueues.isEmpty()) + { + for(Map.Entry<AMQQueue, Map<MessageFilter, Integer>> entry : _filteredQueues.entrySet()) + { + if(!queues.contains(entry.getKey())) + { + for(MessageFilter filter : entry.getValue().keySet()) + { + if(filter.matches(msg)) + { + queues.add(entry.getKey()); + } + } + } + } + } + return queues; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java new file mode 100644 index 0000000000..7e7cb6c0ae --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicNormalizer.java @@ -0,0 +1,96 @@ +/* + * + * 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.qpid.server.exchange.topic; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.AMQShortStringTokenizer; +import org.apache.qpid.server.exchange.TopicExchange; + +import java.util.List; +import java.util.ArrayList; + +public class TopicNormalizer +{ + private static final byte TOPIC_SEPARATOR = (byte)'.'; + private static final byte HASH_BYTE = (byte)'#'; + private static final byte STAR_BYTE = (byte)'*'; + + private static final AMQShortString TOPIC_SEPARATOR_AS_SHORTSTRING = new AMQShortString("."); + private static final AMQShortString AMQP_STAR_TOKEN = new AMQShortString("*"); + private static final AMQShortString AMQP_HASH_TOKEN = new AMQShortString("#"); + + public static AMQShortString normalize(AMQShortString routingKey) + { + if(routingKey == null) + { + return AMQShortString.EMPTY_STRING; + } + else if(!(routingKey.contains(HASH_BYTE) || routingKey.contains(STAR_BYTE))) + { + return routingKey; + } + else + { + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); + + List<AMQShortString> subscriptionList = new ArrayList<AMQShortString>(); + + while (routingTokens.hasMoreTokens()) + { + subscriptionList.add(routingTokens.nextToken()); + } + + int size = subscriptionList.size(); + + for (int index = 0; index < size; index++) + { + // if there are more levels + if ((index + 1) < size) + { + if (subscriptionList.get(index).equals(AMQP_HASH_TOKEN)) + { + if (subscriptionList.get(index + 1).equals(AMQP_HASH_TOKEN)) + { + // we don't need #.# delete this one + subscriptionList.remove(index); + size--; + // redo this normalisation + index--; + } + + if (subscriptionList.get(index + 1).equals(AMQP_STAR_TOKEN)) + { + // we don't want #.* swap to *.# + // remove it and put it in at index + 1 + subscriptionList.add(index + 1, subscriptionList.remove(index)); + } + } + } // if we have more levels + } + + + + AMQShortString normalizedString = AMQShortString.join(subscriptionList, TOPIC_SEPARATOR_AS_SHORTSTRING); + + return normalizedString; + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java new file mode 100644 index 0000000000..c97d71dc39 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -0,0 +1,807 @@ +/* + * + * 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.qpid.server.federation; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.BridgeConfig; +import org.apache.qpid.server.configuration.BridgeConfigType; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.flow.FlowCreditManager_0_10; +import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageAcceptMode; +import org.apache.qpid.transport.MessageAcquireMode; +import org.apache.qpid.transport.MessageCreditUnit; +import org.apache.qpid.transport.MessageFlowMode; +import org.apache.qpid.transport.MessageReject; +import org.apache.qpid.transport.MessageRejectCode; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Option; +import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionException; +import org.apache.qpid.transport.SessionListener; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class Bridge implements BridgeConfig +{ + private final boolean _durable; + private final boolean _dynamic; + private final boolean _queueBridge; + private final boolean _localSource; + private final String _source; + private final String _destination; + private final String _key; + private final String _tag; + private final String _excludes; + private final BrokerLink _link; + private UUID _id; + private long _createTime = System.currentTimeMillis(); + + private Session _session; + + private BridgeImpl _delegate; + + private final int _bridgeNo; + private AutoCommitTransaction _transaction; + + public Bridge(final BrokerLink brokerLink, + final int bridgeNo, + final boolean durable, + final boolean dynamic, + final boolean srcIsQueue, + final boolean srcIsLocal, + final String src, + final String dest, + final String key, + final String tag, + final String excludes) + { + _link = brokerLink; + _bridgeNo = bridgeNo; + _durable = durable; + _dynamic = dynamic; + _queueBridge = srcIsQueue; + _localSource = srcIsLocal; + _source = src; + _destination = dest; + _key = key; + _tag = tag; + _excludes = excludes; + _id = brokerLink.getConfigStore().createId(); + + _transaction = new AutoCommitTransaction(getVirtualHost().getMessageStore()); + + if(dynamic) + { + if(srcIsLocal) + { + // TODO + } + else + { + if(srcIsQueue) + { + // TODO + } + else + { + _delegate = new DynamicExchangeBridge(); + } + } + } + else + { + if(srcIsLocal) + { + if(srcIsQueue) + { + _delegate = new StaticQueuePushBridge(); + } + else + { + _delegate = new StaticExchangePushBridge(); + } + } + else + { + if(srcIsQueue) + { + _delegate = new StaticQueuePullBridge(); + } + else + { + _delegate = new StaticExchangePullBridge(); + } + } + } + } + + public UUID getId() + { + return _id; + } + + public BridgeConfigType getConfigType() + { + return BridgeConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getLink(); + } + + public boolean isDurable() + { + return _durable; + } + + public boolean isDynamic() + { + return _dynamic; + } + + public boolean isQueueBridge() + { + return _queueBridge; + } + + public boolean isLocalSource() + { + return _localSource; + } + + public String getSource() + { + return _source; + } + + public String getDestination() + { + return _destination; + } + + public String getKey() + { + return _key; + } + + public String getTag() + { + return _tag; + } + + public String getExcludes() + { + return _excludes; + } + + public BrokerLink getLink() + { + return _link; + } + + public Integer getChannelId() + { + return (_session == null) ? 0 : _session.getChannel(); + } + + public int getAckBatching() + { + return 0; + } + + public long getCreateTime() + { + return _createTime; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + final Bridge bridge = (Bridge) o; + + if (_durable != bridge._durable) + { + return false; + } + if (_dynamic != bridge._dynamic) + { + return false; + } + if (_localSource != bridge._localSource) + { + return false; + } + if (_queueBridge != bridge._queueBridge) + { + return false; + } + if (_destination != null ? !_destination.equals(bridge._destination) : bridge._destination != null) + { + return false; + } + if (_excludes != null ? !_excludes.equals(bridge._excludes) : bridge._excludes != null) + { + return false; + } + if (_key != null ? !_key.equals(bridge._key) : bridge._key != null) + { + return false; + } + if (_source != null ? !_source.equals(bridge._source) : bridge._source != null) + { + return false; + } + if (_tag != null ? !_tag.equals(bridge._tag) : bridge._tag != null) + { + return false; + } + + return true; + } + + @Override + public int hashCode() + { + int result = (_durable ? 1 : 0); + result = 31 * result + (_dynamic ? 1 : 0); + result = 31 * result + (_queueBridge ? 1 : 0); + result = 31 * result + (_localSource ? 1 : 0); + result = 31 * result + (_source != null ? _source.hashCode() : 0); + result = 31 * result + (_destination != null ? _destination.hashCode() : 0); + result = 31 * result + (_key != null ? _key.hashCode() : 0); + result = 31 * result + (_tag != null ? _tag.hashCode() : 0); + result = 31 * result + (_excludes != null ? _excludes.hashCode() : 0); + return result; + } + + public void setSession(final Session session) + { + _session = session; + _delegate.setSession(session); + } + + private long getMessageWindowSize() + { + return 10l; + } + + + VirtualHost getVirtualHost() + { + return _link.getVirtualHost(); + } + + public void close() + { + // TODO + _delegate.close(); + _session = null; + } + + + private interface BridgeImpl + { + void setSession(Session session); + + void close(); + } + + private abstract class AbstractPullBridge implements BridgeImpl, SessionListener + { + public final void setSession(final Session session) + { + session.setSessionListener(this); + onSession(); + + } + + abstract void onSession(); + + + + public void message(final Session ssn, final MessageTransfer xfr) + { + ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); + + Exchange exchange = exchangeRegistry.getExchange(_destination); + + // TODO - deal with exchange not existing + + DeliveryProperties delvProps = null; + if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) + { + delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl()); + } + + MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); + final MessageStore store = getVirtualHost().getMessageStore(); + StoredMessage<MessageMetaData_0_10> storeMessage = store.addMessage(messageMetaData); + storeMessage.addContent(0,xfr.getBody()); + storeMessage.flushToStore(); + MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)_session).getReference()); + + ArrayList<? extends BaseQueue> queues = exchange.route(message); + + + + if(queues != null && queues.size() != 0) + { + enqueue(message, queues); + } + else + { + if(delvProps == null || !delvProps.hasDiscardUnroutable() || !delvProps.getDiscardUnroutable()) + { + if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT) + { + RangeSet rejects = new RangeSet(); + rejects.add(xfr.getId()); + MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable"); + ssn.invoke(reject); + } + else + { + Exchange alternate = exchange.getAlternateExchange(); + if(alternate != null) + { + queues = alternate.route(message); + if(queues != null && queues.size() != 0) + { + enqueue(message, queues); + } + else + { + //TODO - log the message discard + } + } + else + { + //TODO - log the message discard + } + + + } + } + + + } + + ssn.processed(xfr); + + } + + + private void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues) + { + _transaction.enqueue(queues,message, new ServerTransaction.Action() + { + + BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]); + + public void postCommit() + { + for(int i = 0; i < _queues.length; i++) + { + try + { + _queues[i].enqueue(message); + } + catch (AMQException e) + { + // TODO + + throw new RuntimeException(e); + } + } + } + + public void onRollback() + { + // NO-OP + } + }); + + } + + public void exception(final Session session, final SessionException exception) + { + // TODO - Handle exceptions + } + + public void closed(final Session session) + { + // TODO - handle close + } + + public void opened(final Session session) + { + // this method never called + } + + public void resumed(final Session session) + { + // will never resume these sessions + } + + + + } + + private final class StaticExchangePullBridge extends AbstractPullBridge + { + private final String _tmpQueueName = "bridge_queue_" + _bridgeNo + "_" + _link.getFederationTag();; + + public void onSession() + { + + final HashMap<String, Object> options = new HashMap<String, Object>(); + options.put("qpid.trace.exclude", _link.getFederationTag()); + options.put("qpid.trace.id",_link.getRemoteFederationTag()); + _session.queueDeclare(_tmpQueueName,null, options, Option.AUTO_DELETE, Option.EXCLUSIVE); + _session.sync(); + // todo check exception + final Map<String,Object> bindingArgs = new HashMap<String,Object>(); + _session.exchangeBind(_tmpQueueName, _source, _key, bindingArgs); + _session.sync(); + // todo check exception + + final Map<String,Object> subscribeOptions = Collections.EMPTY_MAP; + final String subName = String.valueOf(_bridgeNo); + _session.messageSubscribe(_tmpQueueName, + subName,MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0l, subscribeOptions); + _session.sync(); + // todo check exception + + _session.messageSetFlowMode(subName,MessageFlowMode.WINDOW); + _session.messageFlow(subName, MessageCreditUnit.MESSAGE, getMessageWindowSize()); + _session.messageFlow(subName, MessageCreditUnit.BYTE, 0xFFFFFFFF); + + } + + public void close() + { + // TODO + } + } + + private final class StaticQueuePullBridge extends AbstractPullBridge + { + + public void onSession() + { + + final Map<String,Object> subscribeOptions = Collections.EMPTY_MAP; + final String subName = String.valueOf(_bridgeNo); + _session.messageSubscribe(_source, + subName,MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0l, subscribeOptions); + _session.sync(); + // todo check exception + + _session.messageSetFlowMode(subName,MessageFlowMode.WINDOW); + _session.messageFlow(subName, MessageCreditUnit.MESSAGE, getMessageWindowSize()); + _session.messageFlow(subName, MessageCreditUnit.BYTE, 0xFFFFFFFF); + + } + + public void close() + { + // TODO + } + } + + private final class DynamicExchangeBridge extends AbstractPullBridge implements Exchange.BindingListener + { + private final String _tmpQueueName = "bridge_queue_" + _bridgeNo + "_" + _link.getFederationTag(); + + private final ConcurrentMap<Binding,Binding> _bindings = new ConcurrentHashMap<Binding,Binding>(); + + + void onSession() + { + + + final HashMap<String, Object> options = new HashMap<String, Object>(); + options.put("qpid.trace.exclude", _link.getFederationTag()); + options.put("qpid.trace.id",_link.getRemoteFederationTag()); + _session.queueDeclare(_tmpQueueName,null, options, Option.AUTO_DELETE, Option.EXCLUSIVE); + _session.sync(); + // todo - check exception + + final Map<String,Object> subscribeOptions = Collections.EMPTY_MAP; + final String subName = String.valueOf(_bridgeNo); + _session.messageSubscribe(_tmpQueueName, + subName,MessageAcceptMode.NONE,MessageAcquireMode.PRE_ACQUIRED,null,0l, subscribeOptions); + _session.sync(); + // todo check exception + _session.messageSetFlowMode(subName,MessageFlowMode.WINDOW); + _session.messageFlow(subName, MessageCreditUnit.MESSAGE, getMessageWindowSize()); + _session.messageFlow(subName, MessageCreditUnit.BYTE, 0xFFFFFFFF); + _session.sync(); + // todo check exception + + + ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); + + Exchange exchange = exchangeRegistry.getExchange(_destination); + + // TODO - check null + + exchange.addBindingListener(this); + + Collection<Binding> bindings = exchange.getBindings(); + for(Binding binding : bindings) + { + propogateBinding(binding); + } + + } + + private void propogateBinding(final Binding binding) + { + if(_bindings.putIfAbsent(binding,binding)== null) + { + Map<String,Object> arguments = new HashMap<String,Object>(binding.getArguments()); + + if(arguments.get("qpid.fed.origin") == null) + { + arguments.put("qpid.fed.op",""); + arguments.put("qpid.fed.origin",_link.getFederationTag()); + arguments.put("qpid.fed.tags",_link.getFederationTag()); + } + else + { + String tags = (String) arguments.get("qpid.fed.tags"); + if(tags == null) + { + tags = _link.getFederationTag(); + } + else + { + if(Arrays.asList(tags.split(",")).contains(_link.getFederationTag())) + { + return; + } + tags += "," + _link.getFederationTag(); + } + arguments.put("qpid.fed.tags", tags); + } + + _session.exchangeBind(_tmpQueueName, _source, binding.getBindingKey(), arguments); + _session.sync(); + // TODO - check exception? + + } + } + + private void propogateBindingRemoval(final Binding binding) + { + if(_bindings.remove(binding) != null) + { + // TODO - this is wrong!!!! + _session.exchangeUnbind(_tmpQueueName, _source, binding.getBindingKey()); + } + } + + + public void bindingAdded(final Exchange exchange, final Binding binding) + { + propogateBinding(binding); + } + + public void bindingRemoved(final Exchange exchange, final Binding binding) + { + propogateBindingRemoval(binding); + } + + public void close() + { + // TODO + } + } + + private class StaticExchangePushBridge implements BridgeImpl, SessionListener + { + private final String _tmpQueueName = "bridge_queue_" + _bridgeNo + "_" + _link.getFederationTag(); + private AMQQueue _queue; + + public void setSession(final Session session) + { + session.setSessionListener(this); + + ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry(); + + Exchange exchange = exchangeRegistry.getExchange(_source); + + // TODO - Check null + + final HashMap<String, Object> options = new HashMap<String, Object>(); + options.put("qpid.trace.exclude", _link.getFederationTag()); + options.put("qpid.trace.id",_link.getRemoteFederationTag()); + + _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName, + isDurable(), + _link.getFederationTag(), + false, + getVirtualHost(), + options); + + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); + + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, + _destination, + MessageAcceptMode.NONE, + MessageAcquireMode.PRE_ACQUIRED, + MessageFlowMode.WINDOW, + creditManager, null); + + ((ServerSession)session).register(_destination, sub); + + try + { + _queue.registerSubscription(sub, true); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + + getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.EMPTY_MAP); + } + + public void close() + { + // TODO + } + + public void opened(final Session session) + { + // this method never called + } + + public void resumed(final Session session) + { + // this session will never be resumed + } + + public void message(final Session ssn, final MessageTransfer xfr) + { + // messages should not be sent ... should probably log error + } + + public void exception(final Session session, final SessionException exception) + { + // TODO + } + + public void closed(final Session session) + { + // TODO + } + } + + private class StaticQueuePushBridge implements BridgeImpl, SessionListener + { + private AMQQueue _queue; + + public void setSession(final Session session) + { + session.setSessionListener(this); + + QueueRegistry queueRegistry = getVirtualHost().getQueueRegistry(); + + _queue = queueRegistry.getQueue(_source); + + // TODO - null check + + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); + + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, + _destination, + MessageAcceptMode.NONE, + MessageAcquireMode.PRE_ACQUIRED, + MessageFlowMode.WINDOW, + creditManager, null); + + ((ServerSession)session).register(_destination, sub); + + try + { + _queue.registerSubscription(sub, false); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + + } + + public void close() + { + // TODO + } + + public void opened(final Session session) + { + // never called + } + + public void resumed(final Session session) + { + // session will not resume + } + + public void message(final Session ssn, final MessageTransfer xfr) + { + // should never be called ... should probably log error + } + + public void exception(final Session session, final SessionException exception) + { + // TODO + } + + public void closed(final Session session) + { + // TODO + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java new file mode 100644 index 0000000000..bb6fb9dcc3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java @@ -0,0 +1,497 @@ +/* + * + * 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.qpid.server.federation; + +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.ConnectionConfigType; +import org.apache.qpid.server.configuration.LinkConfig; +import org.apache.qpid.server.configuration.LinkConfigType; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.Binary; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionException; +import org.apache.qpid.transport.ConnectionListener; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDelegate; +import org.apache.qpid.transport.TransportException; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +public class BrokerLink implements LinkConfig, ConnectionListener +{ + + private static final int CORE_POOL_SIZE = 4; + + private static final ScheduledThreadPoolExecutor _threadPool = + new ScheduledThreadPoolExecutor(CORE_POOL_SIZE); + + + private final String _transport; + private final String _host; + private final int _port; + private final String _remoteVhost; + private final boolean _durable; + private final String _authMechanism; + private final String _username; + private final String _password; + private final VirtualHost _virtualHost; + private UUID _id; + private AtomicBoolean _closing = new AtomicBoolean(); + private final long _createTime = System.currentTimeMillis(); + private Connection _qpidConnection; + private AtomicReference<Thread> _executor = new AtomicReference<Thread>(); + private AtomicInteger _bridgeId = new AtomicInteger(); + + private final ConcurrentHashMap<Bridge,Bridge> _bridges = new ConcurrentHashMap<Bridge,Bridge>(); + private final ConcurrentHashMap<Bridge,Bridge> _activeBridges = new ConcurrentHashMap<Bridge,Bridge>(); + private final ConcurrentLinkedQueue<Bridge> _pendingBridges = new ConcurrentLinkedQueue<Bridge>(); + private String _remoteFederationTag; + + private ConnectionConfig _connectionConfig; + private ConnectionException _exception; + private String _lastErrorMessage; + private int _retryDelay = 1; + private final Runnable _makeConnectionTask = new Runnable() + { + public void run() + { + doMakeConnection(); + } + };; + ; + + public static enum State + { + OPERATIONAL, + DOWN, + ESTABLISHING, + DELETED + } + + + private volatile State _state = State.DOWN; + + private static final AtomicReferenceFieldUpdater<BrokerLink, State> _stateUpdater = + AtomicReferenceFieldUpdater.newUpdater(BrokerLink.class, State.class, "_state"); + + private class ConnectionConfigAdapter implements ConnectionConfig + { + + private UUID _id = BrokerLink.this.getConfigStore().createId(); + + public VirtualHost getVirtualHost() + { + return BrokerLink.this.getVirtualHost(); + } + + public String getAddress() + { + return _host+":"+_port; + } + + public Boolean isIncoming() + { + return false; + } + + public Boolean isSystemConnection() + { + return true; + } + + public Boolean isFederationLink() + { + return true; + } + + public String getAuthId() + { + return _username; + } + + public String getRemoteProcessName() + { + return null; + } + + public Integer getRemotePID() + { + return null; + } + + public Integer getRemoteParentPID() + { + return null; + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public UUID getId() + { + return _id; + } + + public ConnectionConfigType getConfigType() + { + return ConnectionConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + } + + private class SessionFactory implements Connection.SessionFactory + { + + public Session newSession(final Connection conn, final Binary name, final long expiry) + { + return new ServerSession(conn, new SessionDelegate(), name, expiry, _connectionConfig); + } + }; + + + public BrokerLink(final VirtualHost virtualHost, + final String transport, + final String host, + final int port, + final String remoteVhost, + final boolean durable, + final String authMechanism, final String username, final String password) + { + _virtualHost = virtualHost; + _transport = transport; + _host = host; + _port = port; + _remoteVhost = remoteVhost; + _durable = durable; + _authMechanism = authMechanism; + _username = username; + _password = password; + _id = virtualHost.getConfigStore().createId(); + _qpidConnection = new Connection(); + _connectionConfig = new ConnectionConfigAdapter(); + _qpidConnection.addConnectionListener(this); + + + makeConnection(); + } + + private final boolean updateState(State expected, State newState) + { + return _stateUpdater.compareAndSet(this,expected,newState); + } + + private void makeConnection() + { + _threadPool.execute(_makeConnectionTask); + } + + + + private void doMakeConnection() + { + if(updateState(State.DOWN, State.ESTABLISHING)) + { + try + { + _qpidConnection.connect(_host, _port, _remoteVhost, _username, _password, "ssl".equals(_transport), _authMechanism); + + final Map<String,Object> serverProps = _qpidConnection.getServerProperties(); + _remoteFederationTag = (String) serverProps.get("qpid.federation_tag"); + if(_remoteFederationTag == null) + { + _remoteFederationTag = UUID.fromString(_transport+":"+_host+":"+_port).toString(); + } + _qpidConnection.setSessionFactory(new SessionFactory()); + _qpidConnection.setAuthorizationID(_username == null ? "" : _username); + + updateState(State.ESTABLISHING, State.OPERATIONAL); + + _retryDelay = 1; + + for(Bridge bridge : _bridges.values()) + { + if(_state != State.OPERATIONAL) + { + break; + } + addBridge(bridge); + } + + + } + catch (TransportException e) + { + _lastErrorMessage = e.getMessage(); + if(_retryDelay < 60) + { + _retryDelay <<= 1; + } + + updateState(State.ESTABLISHING, State.DOWN); + _activeBridges.clear(); + scheduleConnectionRetry(); + } + } + } + + private void scheduleConnectionRetry() + { + if(_state != State.DELETED) + { + _threadPool.schedule(_makeConnectionTask, _retryDelay, TimeUnit.SECONDS); + } + } + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public String getTransport() + { + return _transport; + } + + public String getHost() + { + return _host; + } + + public int getPort() + { + return _port; + } + + public String getRemoteVhost() + { + return _remoteVhost; + } + + public UUID getId() + { + return _id; + } + + public LinkConfigType getConfigType() + { + return LinkConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return _durable; + } + + public String getAuthMechanism() + { + return _authMechanism; + } + + public String getUsername() + { + return _username; + } + + public String getPassword() + { + return _password; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + final BrokerLink that = (BrokerLink) o; + + if (_port != that._port) + { + return false; + } + if (_host != null ? !_host.equals(that._host) : that._host != null) + { + return false; + } + if (_remoteVhost != null ? !_remoteVhost.equals(that._remoteVhost) : that._remoteVhost != null) + { + return false; + } + if (_transport != null ? !_transport.equals(that._transport) : that._transport != null) + { + return false; + } + + return true; + } + + @Override + public int hashCode() + { + int result = _transport != null ? _transport.hashCode() : 0; + result = 31 * result + (_host != null ? _host.hashCode() : 0); + result = 31 * result + _port; + result = 31 * result + (_remoteVhost != null ? _remoteVhost.hashCode() : 0); + return result; + } + + public void close() + { + if(_closing.compareAndSet(false,true)) + { + // TODO - close connection + for(Bridge bridge : _bridges.values()) + { + bridge.close(); + } + _bridges.clear(); + + _virtualHost.removeBrokerConnection(this); + } + } + + public long getCreateTime() + { + return _createTime; + } + + public void createBridge(final boolean durable, + final boolean dynamic, + final boolean srcIsQueue, + final boolean srcIsLocal, + final String src, + final String dest, + final String key, + final String tag, + final String excludes) + { + if(!_closing.get()) + { + Bridge bridge = new Bridge(this, _bridgeId.incrementAndGet(), durable,dynamic,srcIsQueue,srcIsLocal,src,dest,key,tag,excludes); + if(_bridges.putIfAbsent(bridge, bridge) == null) + { + + addBridge(bridge); + } + } + + + } + + private void addBridge(final Bridge bridge) + { + getConfigStore().addConfiguredObject(bridge); + + if(_state == State.OPERATIONAL && (_activeBridges.putIfAbsent(bridge,bridge) == null)) + { + + + Session session = _qpidConnection.createSession("Bridge(" + + (bridge.isDurable() ? "durable" : "transient") + + "," + (bridge.isDynamic() ? "dynamic" : "static") + + "," + (bridge.isQueueBridge() ? "queue" : "exchange") + + "," + (bridge.isLocalSource() ? "local-src" : "remote-src") + + ",[Source: '" + bridge.getSource() + "']" + + ",[Destination: '" + bridge.getDestination() + "']" + + ",[Key: '" + bridge.getKey() + "']" + + ",[Tag: '" + bridge.getTag() + "']" + + ".[Excludes: '" + bridge.getExcludes() + "'])"); + bridge.setSession(session); + + + if(_closing.get()) + { + bridge.close(); + } + } + + } + + public void opened(final Connection connection) + { + // this method not called + } + + public void exception(final Connection connection, final ConnectionException exception) + { + _exception = exception; + _lastErrorMessage = exception.getMessage(); + + } + + public void closed(final Connection connection) + { + State currentState = _state; + if(currentState != State.DOWN && currentState != State.DELETED && updateState(currentState, State.DOWN)) + { + scheduleConnectionRetry(); + } + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public String getFederationTag() + { + return getVirtualHost().getFederationTag(); + } + + public String getRemoteFederationTag() + { + return _remoteFederationTag; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index dacd047fea..f32de03841 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.server.filter.jms.selector.SelectorParser; import org.apache.qpid.server.queue.Filterable; @@ -33,7 +34,7 @@ public class JMSSelectorFilter implements MessageFilter private String _selector; private BooleanExpression _matcher; - public JMSSelectorFilter(String selector) throws AMQException + public JMSSelectorFilter(String selector) throws AMQInvalidArgumentException { _selector = selector; _matcher = new SelectorParser().parse(selector); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 0343457a73..d806f9426a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -27,7 +27,6 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -102,11 +101,11 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic body.getNoLocal(), body.getNowait(), queue)) { throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } + } else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue " + queue.getName() + " is exclusive, but not created on this Connection."); + "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); } if (body.getConsumerTag() != null) @@ -163,14 +162,14 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic { throw body.getChannelException(AMQConstant.ACCESS_REFUSED, "Cannot subscribe to queue " - + queue.getName() + + queue.getNameShortString() + " as it already has an existing exclusive consumer"); } catch (AMQQueue.ExistingSubscriptionPreventsExclusive e) { throw body.getChannelException(AMQConstant.ACCESS_REFUSED, "Cannot subscribe to queue " - + queue.getName() + + queue.getNameShortString() + " exclusively as it already has a consumer"); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index 1dd6f1413b..7cfd1fc121 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -30,7 +30,6 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -109,10 +108,10 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange } } } - else if (!exchange.getType().equals(body.getType())) + else if (!exchange.getTypeShortString().equals(body.getType())) { - throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null); + throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getTypeShortString() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java index 57ce7a7240..0de3ded5a1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -7,9 +7,9 @@ * 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 @@ -21,21 +21,27 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidRoutingKeyException; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.QueueBindBody; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Map; + public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody> { private static final Logger _log = Logger.getLogger(QueueBindHandler.class); @@ -80,7 +86,7 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody> if (body.getRoutingKey() == null) { - routingKey = queue.getName(); + routingKey = queue.getNameShortString(); } else { @@ -116,18 +122,26 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody> else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue " + queue.getName() + " is exclusive, but not created on this Connection."); + "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); } if (!exch.isBound(routingKey, body.getArguments(), queue)) { - queue.bind(exch, routingKey, body.getArguments()); + String bindingKey = String.valueOf(routingKey); + Map<String,Object> arguments = FieldTable.convertToMap(body.getArguments()); + + if(!virtualHost.getBindingFactory().addBinding(bindingKey, queue, exch, arguments)) + { + Binding oldBinding = virtualHost.getBindingFactory().getBinding(bindingKey, queue, exch, arguments); + + Map<String, Object> oldArgs = oldBinding.getArguments(); + if((oldArgs == null && !arguments.isEmpty()) || (oldArgs != null && !oldArgs.equals(arguments))) + { + virtualHost.getBindingFactory().replaceBinding(bindingKey, queue, exch, arguments); + } + } } } - catch (AMQInvalidRoutingKeyException rke) - { - throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); - } catch (AMQException e) { throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index bb57fdbc36..5d5bd761c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.handler; import java.util.UUID; +import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; @@ -150,21 +151,21 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar { Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); - queue.bind(defaultExchange, queueName, null); - _logger.info("Queue " + queueName + " bound to default exchange(" + defaultExchange.getName() + ")"); + virtualHost.getBindingFactory().addBinding(String.valueOf(queueName), queue, defaultExchange, Collections.EMPTY_MAP); + _logger.info("Queue " + queueName + " bound to default exchange(" + defaultExchange.getNameShortString() + ")"); } } } else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue " + queue.getName() + " is exclusive, but not created on this Connection."); + "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); } else if(!body.getPassive() && ((queue.isExclusive()) != body.getExclusive())) { throw body.getChannelException(AMQConstant.ALREADY_EXISTS, - "Cannot re-declare queue '" + queue.getName() + "' with different exclusivity (was: " + "Cannot re-declare queue '" + queue.getNameShortString() + "' with different exclusivity (was: " + queue.isExclusive() + " requested " + body.getExclusive() + ")"); } else if (!body.getPassive() && body.getExclusive() && !queue.getExclusiveOwner().equals(queue.isDurable() ? session.getPrincipal().getName() : session)) @@ -178,13 +179,13 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar else if(!body.getPassive() && queue.isAutoDelete() != body.getAutoDelete()) { throw body.getChannelException(AMQConstant.ALREADY_EXISTS, - "Cannot re-declare queue '" + queue.getName() + "' with different auto-delete (was: " + "Cannot re-declare queue '" + queue.getNameShortString() + "' with different auto-delete (was: " + queue.isAutoDelete() + " requested " + body.getAutoDelete() + ")"); } else if(!body.getPassive() && queue.isDurable() != body.getDurable()) { throw body.getChannelException(AMQConstant.ALREADY_EXISTS, - "Cannot re-declare queue '" + queue.getName() + "' with different durability (was: " + "Cannot re-declare queue '" + queue.getNameShortString() + "' with different durability (was: " + queue.isDurable() + " requested " + body.getDurable() + ")"); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index 3d58ec2133..93acc94816 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -7,9 +7,9 @@ * 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 @@ -30,11 +30,9 @@ import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.security.access.Permission; public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteBody> { @@ -75,7 +73,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB throw body.getChannelNotFoundException(channelId); } - //get the default queue on the channel: + //get the default queue on the channel: queue = channel.getDefaultQueue(); } else @@ -104,7 +102,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB } else { - + //Perform ACLs if (!virtualHost.getAccessManager().authoriseDelete(session, queue)) { @@ -113,7 +111,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB else if (queue.isExclusive() && !queue.isDurable() && queue.getExclusiveOwner() != session) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, - "Queue " + queue.getName() + " is exclusive, but not created on this Connection."); + "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); } int purged = queue.delete(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java index 31401ce9d9..29c30de9cc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -106,23 +106,16 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); } - try + if(virtualHost.getBindingFactory().getBinding(String.valueOf(routingKey), queue, exch, FieldTable.convertToMap(body.getArguments())) == null) { - queue.unBind(exch, routingKey, body.getArguments()); + throw body.getChannelException(AMQConstant.NOT_FOUND,"No such binding"); } - catch (AMQInvalidRoutingKeyException rke) - { - throw body.getChannelException(AMQConstant.INVALID_ROUTING_KEY, routingKey.toString()); - } - catch (AMQException e) + else { - if(e.getErrorCode() == AMQConstant.NOT_FOUND) - { - throw body.getChannelException(AMQConstant.NOT_FOUND,e.getMessage(),e); - } - throw body.getChannelException(AMQConstant.CHANNEL_ERROR, e.toString()); + virtualHost.getBindingFactory().removeBinding(String.valueOf(routingKey), queue, exch, FieldTable.convertToMap(body.getArguments())); } + if (_log.isInfoEnabled()) { _log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java index fd171fea5a..69139d38a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/BindingLogSubject.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.logging.subjects; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; @@ -49,13 +48,13 @@ public class BindingLogSubject extends AbstractLogSubject * @param exchange * @param queue */ - public BindingLogSubject(AMQShortString routingKey, Exchange exchange, + public BindingLogSubject(String routingKey, Exchange exchange, AMQQueue queue) { setLogStringWithFormat(BINDING_FORMAT, queue.getVirtualHost().getName(), - exchange.getType(), - exchange.getName(), - queue.getName(), + exchange.getTypeShortString(), + exchange.getNameShortString(), + queue.getNameShortString(), routingKey); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java index 21e5f5e4ce..0fc2d7392f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ExchangeLogSubject.java @@ -41,6 +41,6 @@ public class ExchangeLogSubject extends AbstractLogSubject public ExchangeLogSubject(Exchange exchange, VirtualHost vhost) { setLogStringWithFormat(BINDING_FORMAT, vhost.getName(), - exchange.getType(), exchange.getName()); + exchange.getTypeShortString(), exchange.getNameShortString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java index b132d9e93f..fd97318e8b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/QueueLogSubject.java @@ -40,6 +40,6 @@ public class QueueLogSubject extends AbstractLogSubject { setLogStringWithFormat(LOG_FORMAT, queue.getVirtualHost().getName(), - queue.getName()); + queue.getNameShortString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java index 6c9311c3de..faac14f8a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java @@ -42,6 +42,10 @@ public interface AMQMessageHeader String getReplyTo(); + String getReplyToExchange(); + String getReplyToRoutingKey(); + + Object getHeader(String name); boolean containsHeaders(Set<String> names); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java index 4a1f8dd191..194835ac02 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java @@ -85,6 +85,19 @@ public class ContentHeaderBodyAdapter implements AMQMessageHeader return getProperties().getReplyToAsString(); } + public String getReplyToExchange() + { + // TODO + return getReplyTo(); + } + + public String getReplyToRoutingKey() + { + // TODO + return getReplyTo(); + + } + public Object getHeader(String name) { FieldTable ft = getProperties().getHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java index b34a8fc470..2f8c2e09a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -278,6 +278,18 @@ public class MessageMetaData implements StorableMessageMetaData return getProperties().getReplyToAsString(); } + public String getReplyToExchange() + { + // TODO + return getReplyTo(); + } + + public String getReplyToRoutingKey() + { + // TODO + return getReplyTo(); + } + public Object getHeader(String name) { FieldTable ft = getProperties().getHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java index 7fac7ab164..a15e16a64f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -105,6 +105,30 @@ class MessageTransferHeader implements AMQMessageHeader } } + public String getReplyToExchange() + { + if (_messageProps != null && _messageProps.getReplyTo() != null) + { + return _messageProps.getReplyTo().getExchange(); + } + else + { + return null; + } + } + + public String getReplyToRoutingKey() + { + if (_messageProps != null && _messageProps.getReplyTo() != null) + { + return _messageProps.getReplyTo().getRoutingKey(); + } + else + { + return null; + } + } + public Object getHeader(String name) { Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java index e866ad5078..baa5dce14f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java @@ -119,7 +119,7 @@ public class MessageTransferMessage implements InboundMessage, ServerMessage public ByteBuffer getBody() { ByteBuffer body = getMetaData().getBody(); - if(body == null) + if(body == null && getSize() != 0l) { final int size = (int) getSize(); int pos = 0; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index ea8fbbd68f..ec74f79ace 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -20,50 +20,16 @@ */ package org.apache.qpid.server.protocol; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicMarkableReference; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.management.JMException; -import javax.security.sasl.SaslServer; - import org.apache.log4j.Logger; import org.apache.mina.transport.vmpipe.VmPipeAddress; + import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.framing.AMQProtocolHeaderException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ChannelCloseOkBody; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.HeartbeatBody; -import org.apache.qpid.framing.MethodDispatcher; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.framing.ProtocolInitiation; -import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.framing.*; import org.apache.qpid.pool.Job; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.protocol.AMQConstant; @@ -71,6 +37,10 @@ import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.ConnectionConfigType; import org.apache.qpid.server.handler.ServerMethodDispatcherImpl; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; @@ -85,12 +55,31 @@ import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.Sender; -public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession +import javax.management.JMException; +import javax.security.sasl.SaslServer; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession, ConnectionConfig { private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class); @@ -161,6 +150,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); private long _maxFrameSize; private final AtomicBoolean _closing = new AtomicBoolean(false); + private final UUID _id; + private final ConfigStore _configStore; public ManagedObject getManagedObject() { @@ -181,6 +172,10 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _logSubject = new ConnectionLogSubject(this); + _configStore = virtualHostRegistry.getConfigStore(); + _id = _configStore.createId(); + + _actor.message(ConnectionMessages.CON_OPEN(null, null, false, false)); } @@ -765,6 +760,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void closeProtocolSession() { + getConfigStore().removeConfiguredObject(this); + _networkDriver.close(); try { @@ -902,6 +899,8 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _virtualHost = virtualHost; _virtualHost.getConnectionRegistry().registerConnection(this); + + _configStore.addConfiguredObject(this); try { @@ -1067,4 +1066,69 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } } + public Boolean isIncoming() + { + return true; + } + + public Boolean isSystemConnection() + { + return false; + } + + public Boolean isFederationLink() + { + return false; + } + + public String getAuthId() + { + return getAuthorizedID().getName(); + } + + public Integer getRemotePID() + { + return null; + } + + public String getRemoteProcessName() + { + return null; + } + + public Integer getRemoteParentPID() + { + return null; + } + + public ConfigStore getConfigStore() + { + return _configStore; + } + + public ConnectionConfigType getConfigType() + { + return ConnectionConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + + public UUID getId() + { + return _id; + } + + public String getAddress() + { + return String.valueOf(getRemoteAddress()); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 0562d04b7b..8d832a6a79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -37,8 +37,19 @@ */ package org.apache.qpid.server.protocol; -import java.util.Date; -import java.util.List; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; import javax.management.JMException; import javax.management.MBeanException; @@ -55,22 +66,8 @@ import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; +import java.util.Date; +import java.util.List; /** * This MBean class implements the management interface. In order to make more attributes, operations and notifications @@ -255,7 +252,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed Object[] itemValues = { channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, + (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getNameShortString().asString() : null, channel.getUnacknowledgedMessageMap().size(), channel.getBlocking() }; @@ -291,7 +288,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed // then the CurrentActor could be set in our JMX Proxy object. // As it is we need to set the CurrentActor on all MBean methods // Ideally we would not have a single method that can be called from - // two contexts. + // two contexts. boolean removeActor = false; if (CurrentActor.get() == null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java index 9a1c6c9418..b3cb90fc6e 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -20,14 +20,14 @@ */ package org.apache.qpid.server.protocol; +import org.apache.log4j.Logger; + import org.apache.qpid.protocol.ProtocolEngine; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.transport.NetworkDriver; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.ConnectionDelegate; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; +import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.transport.ServerConnection; -import org.apache.log4j.Logger; +import org.apache.qpid.transport.ConnectionDelegate; +import org.apache.qpid.transport.NetworkDriver; import java.net.SocketAddress; import java.nio.ByteBuffer; @@ -239,10 +239,10 @@ private static final byte[] AMQP_0_9_1_HEADER = final ConnectionDelegate connDelegate = new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn); - Connection conn = new ServerConnection(); + ServerConnection conn = new ServerConnection(); conn.setConnectionDelegate(connDelegate); - return new ProtocolEngine_0_10( conn, _networkDriver); + return new ProtocolEngine_0_10( conn, _networkDriver, _appRegistry); } }; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java deleted file mode 100755 index 7c3adf8b7d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * 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.qpid.server.protocol; - -import org.apache.qpid.protocol.ProtocolEngineFactory; -import org.apache.qpid.protocol.ProtocolEngine; -import org.apache.qpid.transport.NetworkDriver; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.ConnectionDelegate; -import org.apache.qpid.server.transport.ServerConnection; -import org.apache.qpid.server.protocol.ProtocolEngine_0_10; - -public class ProtocolEngineFactory_0_10 implements ProtocolEngineFactory -{ - private ConnectionDelegate _delegate; - - public ProtocolEngineFactory_0_10(ConnectionDelegate delegate) - { - _delegate = delegate; - } - - public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) - { - Connection conn = new ServerConnection(); - conn.setConnectionDelegate(_delegate); - return new ProtocolEngine_0_10(conn, networkDriver); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java index e3cd3acd98..473f68028d 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -26,23 +26,34 @@ import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.network.InputHandler; import org.apache.qpid.transport.network.Assembler; import org.apache.qpid.transport.network.Disassembler; +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.qpid.server.registry.IApplicationRegistry; import java.net.SocketAddress; +import java.util.UUID; -public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine +public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine, ConnectionConfig { public static final int MAX_FRAME_SIZE = 64 * 1024 - 1; private NetworkDriver _networkDriver; private long _readBytes; private long _writtenBytes; - private Connection _connection; + private ServerConnection _connection; + private final UUID _id; + private final IApplicationRegistry _appRegistry; - public ProtocolEngine_0_10(Connection conn, NetworkDriver networkDriver) + public ProtocolEngine_0_10(ServerConnection conn, + NetworkDriver networkDriver, + final IApplicationRegistry appRegistry) { super(new Assembler(conn)); _connection = conn; + _connection.setConnectionConfig(this); _networkDriver = networkDriver; + _id = appRegistry.getConfigStore().createId(); + _appRegistry = appRegistry; } public void setNetworkDriver(NetworkDriver driver) @@ -50,6 +61,14 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine _networkDriver = driver; Disassembler dis = new Disassembler(driver, MAX_FRAME_SIZE); _connection.setSender(dis); + _connection.onOpen(new Runnable() + { + public void run() + { + getConfigStore().addConfiguredObject(ProtocolEngine_0_10.this); + } + }); + } public SocketAddress getRemoteAddress() @@ -81,4 +100,81 @@ public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine { //Todo } + + public VirtualHostConfig getVirtualHost() + { + return _connection.getVirtualHost(); + } + + public String getAddress() + { + return getRemoteAddress().toString(); + } + + public Boolean isIncoming() + { + return true; + } + + public Boolean isSystemConnection() + { + return false; + } + + public Boolean isFederationLink() + { + return false; + } + + public String getAuthId() + { + return _connection.getAuthorizationID(); + } + + public String getRemoteProcessName() + { + return null; + } + + public Integer getRemotePID() + { + return null; + } + + public Integer getRemoteParentPID() + { + return null; + } + + public ConfigStore getConfigStore() + { + return _appRegistry.getConfigStore(); + } + + public UUID getId() + { + return _id; + } + + public ConnectionConfigType getConfigType() + { + return ConnectionConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + + @Override + public void closed() + { + super.closed(); + getConfigStore().removeConfiguredObject(this); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index 51fbff76f4..d8986ec303 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -21,9 +21,11 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.subscription.SubscriptionList; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Map; public class AMQPriorityQueue extends SimpleAMQQueue { @@ -32,18 +34,18 @@ public class AMQPriorityQueue extends SimpleAMQQueue final AMQShortString owner, final boolean autoDelete, final VirtualHost virtualHost, - int priorities) + int priorities, Map<String, Object> arguments) { - super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); + super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities),arguments); } public AMQPriorityQueue(String queueName, boolean durable, String owner, boolean autoDelete, - VirtualHost virtualHost, int priorities) + VirtualHost virtualHost, int priorities, Map<String,Object> arguments) { - this(new AMQShortString(queueName), durable, new AMQShortString(owner),autoDelete,virtualHost,priorities); + this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost,priorities, arguments); } public int getPriorities() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 028f7e15a4..81ea2083e0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,44 +20,48 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.QueueConfig; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeReferrer; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.management.Managable; +import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.List; -import java.util.Set; import java.util.Map; +import java.util.Set; -public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeReferrer, TransactionLogResource +public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeReferrer, TransactionLogResource, BaseQueue, + QueueConfig { boolean getDeleteOnNoConsumers(); void setDeleteOnNoConsumers(boolean b); + void addBinding(Binding binding); + + void removeBinding(Binding binding); + + List<Binding> getBindings(); + + int getBindingCount(); public interface Context { QueueEntry getLastSeenEntry(); } - AMQShortString getName(); - void setNoLocal(boolean b); - boolean isDurable(); - boolean isAutoDelete(); AMQShortString getOwner(); @@ -69,14 +73,6 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer VirtualHost getVirtualHost(); - - void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - - void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException; - - List<ExchangeBinding> getExchangeBindings(); - - void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException; void unregisterSubscription(final Subscription subscription) throws AMQException; @@ -86,6 +82,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer int getActiveConsumerCount(); + boolean hasExclusiveSubscriber(); + boolean isUnused(); boolean isEmpty(); @@ -107,8 +105,6 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer int delete() throws AMQException; - QueueEntry enqueue(ServerMessage message) throws AMQException; - void requeue(QueueEntry entry); void requeue(QueueEntryImpl storeContext, Subscription subscription); @@ -122,6 +118,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void addQueueDeleteTask(final Task task); + void removeQueueDeleteTask(final Task task); + List<QueueEntry> getMessagesOnTheQueue(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index d4a5b3258b..fd7dd4cc60 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -23,16 +23,21 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.configuration.QueueConfiguration; import java.util.Map; +import java.util.HashMap; public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); + private static final String QPID_LVQ_KEY = "qpid.LVQ_key"; + private static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue"; + private static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key"; + private abstract static class QueueProperty { @@ -130,21 +135,60 @@ public class AMQQueueFactory boolean autoDelete, VirtualHost virtualHost, final FieldTable arguments) { - final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; + return createAMQQueueImpl(name == null ? null : name.toString(), + durable, + owner == null ? null : owner.toString(), + autoDelete, + virtualHost, + FieldTable.convertToMap(arguments)); + } - AMQQueue q = null; - if(priorities > 1) + + public static AMQQueue createAMQQueueImpl(String queueName, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, Map<String, Object> arguments) + { + int priorities = 1; + String conflationKey = null; + if(arguments != null) { - q = new AMQPriorityQueue(name, durable, owner, autoDelete, virtualHost, priorities); + if(arguments.containsKey(QPID_LAST_VALUE_QUEUE) || arguments.containsKey(QPID_LAST_VALUE_QUEUE_KEY)) + { + conflationKey = (String) arguments.get(QPID_LAST_VALUE_QUEUE_KEY); + if(conflationKey == null) + { + conflationKey = QPID_LVQ_KEY; + } + } + else if(arguments.containsKey(X_QPID_PRIORITIES)) + { + Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); + if(prioritiesObj instanceof Number) + { + priorities = ((Number)prioritiesObj).intValue(); + } + } + } + + AMQQueue q; + if(conflationKey != null) + { + q = new ConflationQueue(queueName, durable, owner, autoDelete, virtualHost, arguments, conflationKey); + } + else if(priorities > 1) + { + q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities, arguments); } else { - q = new SimpleAMQQueue(name, durable, owner, autoDelete, virtualHost); + q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost, arguments); } //Register the new queue virtualHost.getQueueRegistry().registerQueue(q); - q.configure(virtualHost.getConfiguration().getQueueConfiguration(name.asString())); + q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName)); if(arguments != null) { @@ -158,29 +202,43 @@ public class AMQQueueFactory } return q; + } + public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException { - AMQShortString queueName = new AMQShortString(config.getName()); + String queueName = config.getName(); boolean durable = config.getDurable(); boolean autodelete = config.getAutoDelete(); - AMQShortString owner = (config.getOwner() != null) ? new AMQShortString(config.getOwner()) : null; - FieldTable arguments = null; - boolean priority = config.getPriority(); - int priorities = config.getPriorities(); - if(priority || priorities > 0) + String owner = config.getOwner(); + Map<String,Object> arguments = null; + if(config.isLVQ() || config.getLVQKey() != null) { if(arguments == null) { - arguments = new FieldTable(); + arguments = new HashMap<String,Object>(); } - if (priorities < 0) + arguments.put(QPID_LAST_VALUE_QUEUE, 1); + arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey()); + } + else + { + boolean priority = config.getPriority(); + int priorities = config.getPriorities(); + if(priority || priorities > 0) { - priorities = 10; + if(arguments == null) + { + arguments = new HashMap<String,Object>(); + } + if (priorities < 0) + { + priorities = 10; + } + arguments.put("x-qpid-priorities", priorities); } - arguments.put(new AMQShortString("x-qpid-priorities"), priorities); } AMQQueue q = createAMQQueueImpl(queueName, durable, owner, autodelete, host, arguments); @@ -188,38 +246,4 @@ public class AMQQueueFactory return q; } - public static AMQQueue createAMQQueueImpl(String queueName, - boolean durable, - String owner, - boolean autoDelete, - VirtualHost virtualHost, Map<String, Object> arguments) - throws AMQException - { - int priorities = 1; - if(arguments != null && arguments.containsKey(X_QPID_PRIORITIES)) - { - Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); - if(prioritiesObj instanceof Number) - { - priorities = ((Number)prioritiesObj).intValue(); - } - } - - - AMQQueue q = null; - if(priorities > 1) - { - q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities); - } - else - { - q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost); - } - - //Register the new queue - virtualHost.getQueueRegistry().registerQueue(q); - q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName)); - return q; - - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index c21d73cc41..6102e525e3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -95,7 +95,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { super(ManagedQueue.class, ManagedQueue.TYPE); _queue = queue; - _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); + _queueName = jmxEncode(new StringBuffer(queue.getNameShortString()), 0).toString(); } public ManagedObject getParentObject() @@ -252,7 +252,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { throw new IllegalArgumentException("Capacity must not be less than FlowResumeCapacity"); } - + _queue.setCapacity(capacity); } @@ -267,10 +267,10 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { throw new IllegalArgumentException("FlowResumeCapacity must not exceed Capacity"); } - + _queue.setFlowResumeCapacity(flowResumeCapacity); } - + public boolean isFlowOverfull() { return _queue.isOverfull(); @@ -309,7 +309,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) { // important : add log to the log file - monitoring tools may be looking for this - _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); + _logger.info(notification.name() + " On Queue " + queue.getNameShortString() + " - " + notificationMsg); notificationMsg = notification.name() + " " + notificationMsg; _lastNotification = @@ -509,7 +509,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private String[] getMessageTransferMessageHeaderProps(MessageTransferMessage msg) { List<String> list = new ArrayList<String>(); - + AMQMessageHeader header = msg.getMessageHeader(); MessageProperties msgProps = msg.getHeader().get(MessageProperties.class); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java new file mode 100644 index 0000000000..05e0efd9a6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java @@ -0,0 +1,42 @@ +/* + * + * 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.qpid.server.queue; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; + +public interface BaseQueue extends TransactionLogResource +{ + public static interface PostEnqueueAction + { + public void onEnqueue(QueueEntry entry); + } + + void enqueue(ServerMessage message) throws AMQException; + void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException; + + boolean isDurable(); + + AMQShortString getNameShortString(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java new file mode 100644 index 0000000000..26c0d7cf26 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java @@ -0,0 +1,42 @@ +/* + * + * 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.qpid.server.queue; + +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Map; + +public class ConflationQueue extends SimpleAMQQueue +{ + protected ConflationQueue(String name, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, + Map<String, Object> args, + String conflationKey) + { + super(name, durable, owner, autoDelete, virtualHost, new ConflationQueueList.Factory(conflationKey), args); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java new file mode 100644 index 0000000000..9a6e5c884a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java @@ -0,0 +1,168 @@ +/* + * + * 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.qpid.server.queue; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.message.ServerMessage; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; + +public class ConflationQueueList extends SimpleQueueEntryList +{ + + private final String _conflationKey; + private final ConcurrentHashMap<Object, AtomicReference<QueueEntry>> _latestValuesMap = + new ConcurrentHashMap<Object, AtomicReference<QueueEntry>>(); + + public ConflationQueueList(AMQQueue queue, String conflationKey) + { + super(queue); + _conflationKey = conflationKey; + } + + @Override + protected ConflationQueueEntry createQueueEntry(ServerMessage message) + { + return new ConflationQueueEntry(this, message); + } + + + @Override + public QueueEntry add(final ServerMessage message) + { + ConflationQueueEntry entry = (ConflationQueueEntry) (super.add(message)); + AtomicReference<QueueEntry> latestValueReference = null; + + Object value = message.getMessageHeader().getHeader(_conflationKey); + if(value != null) + { + latestValueReference = _latestValuesMap.get(value); + if(latestValueReference == null) + { + _latestValuesMap.putIfAbsent(value, new AtomicReference<QueueEntry>(entry)); + latestValueReference = _latestValuesMap.get(value); + } + QueueEntry oldEntry; + + do + { + oldEntry = latestValueReference.get(); + } + while(oldEntry.compareTo(entry) < 0 && !latestValueReference.compareAndSet(oldEntry, entry)); + + if(oldEntry.compareTo(entry) < 0) + { + // We replaced some other entry to become the newest value + if(oldEntry.acquire()) + { + discardEntry(oldEntry); + } + } + else if (oldEntry.compareTo(entry) > 0) + { + // A newer entry came along + discardEntry(entry); + + } + } + + entry.setLatestValueReference(latestValueReference); + return entry; + } + + private void discardEntry(final QueueEntry entry) + { + if(entry.acquire()) + { + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + txn.dequeue(entry.getQueue(),entry.getMessage(), + new ServerTransaction.Action() + { + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + + } + }); + } + } + + private final class ConflationQueueEntry extends QueueEntryImpl + { + + + private AtomicReference<QueueEntry> _latestValueReference; + + public ConflationQueueEntry(SimpleQueueEntryList queueEntryList, ServerMessage message) + { + super(queueEntryList, message); + } + + + public void release() + { + super.release(); + + if(_latestValueReference != null) + { + if(_latestValueReference.get() != this) + { + discardEntry(this); + } + } + + } + + public void setLatestValueReference(final AtomicReference<QueueEntry> latestValueReference) + { + _latestValueReference = latestValueReference; + } + } + + static class Factory implements QueueEntryListFactory + { + private final String _conflationKey; + + Factory(String conflationKey) + { + _conflationKey = conflationKey; + } + + public QueueEntryList createQueueEntryList(AMQQueue queue) + { + return new ConflationQueueList(queue, _conflationKey); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index aea485e749..d76487073d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -46,7 +45,7 @@ public class DefaultQueueRegistry implements QueueRegistry public void registerQueue(AMQQueue queue) { - _queueMap.put(queue.getName(), queue); + _queueMap.put(queue.getNameShortString(), queue); } public void unregisterQueue(AMQShortString name) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java deleted file mode 100644 index 2fd8e32fcd..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBinding.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * 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.qpid.server.queue; - -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.BindingMessages; -import org.apache.qpid.server.logging.subjects.BindingLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; - -public class ExchangeBinding -{ - private final Exchange _exchange; - private final AMQShortString _routingKey; - private final FieldTable _arguments; - - private static final FieldTable EMPTY_ARGUMENTS = new FieldTable(); - private LogSubject _logSubject; - - ExchangeBinding(AMQShortString routingKey, Exchange exchange, AMQQueue queue, FieldTable arguments) - { - _routingKey = routingKey == null ? AMQShortString.EMPTY_STRING : routingKey; - _exchange = exchange; - _arguments = arguments == null ? EMPTY_ARGUMENTS : arguments; - _logSubject = new BindingLogSubject(routingKey,exchange,queue); - - CurrentActor.get().message(_logSubject, BindingMessages.BND_CREATED(String.valueOf(_arguments), arguments != null)); - } - - - - void unbind(AMQQueue queue) throws AMQException - { - _exchange.deregisterQueue(_routingKey, queue, _arguments); - - CurrentActor.get().message(_logSubject, BindingMessages.BND_DELETED()); - } - - public Exchange getExchange() - { - return _exchange; - } - - public AMQShortString getRoutingKey() - { - return _routingKey; - } - - public FieldTable getArguments() - { - return _arguments; - } - - public int hashCode() - { - return (_exchange == null ? 0 : _exchange.hashCode()) - + (_routingKey == null ? 0 : _routingKey.hashCode()); - } - - public boolean equals(Object o) - { - if (!(o instanceof ExchangeBinding)) - { - return false; - } - ExchangeBinding eb = (ExchangeBinding) o; - return _exchange.equals(eb._exchange) - && _routingKey.equals(eb._routingKey); - } -}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java deleted file mode 100644 index 89262aee59..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ExchangeBindings.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * 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.qpid.server.queue; - -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.Exchange; - -/** - * When a queue is deleted, it should be deregistered from any - * exchange it has been bound to. This class assists in this task, - * by keeping track of all bindings for a given queue. - */ -class ExchangeBindings -{ - private final List<ExchangeBinding> _bindings = new CopyOnWriteArrayList<ExchangeBinding>(); - private final AMQQueue _queue; - - ExchangeBindings(AMQQueue queue) - { - _queue = queue; - } - - /** - * Adds the specified binding to those being tracked. - * @param routingKey the routing key with which the queue whose bindings - * are being tracked by the instance has been bound to the exchange - * @param exchange the exchange bound to - */ - void addBinding(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - _bindings.add(new ExchangeBinding(routingKey, exchange, _queue, arguments)); - } - - - public boolean remove(AMQShortString routingKey, FieldTable arguments, Exchange exchange) - { - return _bindings.remove(new ExchangeBinding(routingKey, exchange, _queue, arguments)); - } - - - /** - * Deregisters this queue from any exchange it has been bound to - */ - void deregister() throws AMQException - { - //remove duplicates at this point - HashSet<ExchangeBinding> copy = new HashSet<ExchangeBinding>(_bindings); - for (ExchangeBinding b : copy) - { - b.unbind(_queue); - } - } - - List<ExchangeBinding> getExchangeBindings() - { - return _bindings; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index da4173d5d3..2d2fb3a214 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -63,7 +63,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes * delivered. It is <b>cleared after delivery has been attempted</b>. Any persistent record of destinations is done * by the message handle. */ - private ArrayList<AMQQueue> _destinationQueues; + private ArrayList<? extends BaseQueue> _destinationQueues; private long _expiration; @@ -131,7 +131,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes } - public ArrayList<AMQQueue> getDestinationQueues() + public ArrayList<? extends BaseQueue> getDestinationQueues() { return _destinationQueues; } @@ -225,7 +225,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes } - public void enqueue(final ArrayList<AMQQueue> queues) + public void enqueue(final ArrayList<? extends BaseQueue> queues) { _destinationQueues = queues; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index a50e2b561d..edd1e0bdc3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -28,6 +28,7 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { + public static enum State { AVAILABLE, @@ -163,6 +164,8 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable boolean expired() throws AMQException; + boolean isAvailable(); + boolean isAcquired(); boolean acquire(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 5873e8f566..ada7726fc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -20,20 +20,23 @@ */ package org.apache.qpid.server.queue; +import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.log4j.Logger; -import java.util.*; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class QueueEntryImpl implements QueueEntry @@ -154,6 +157,11 @@ public class QueueEntryImpl implements QueueEntry } + public boolean isAvailable() + { + return _state == AVAILABLE_STATE; + } + public boolean isAcquired() { return _state.getState() == State.ACQUIRED; @@ -408,7 +416,7 @@ public class QueueEntryImpl implements QueueEntry if(alternateExchange != null) { - final List<AMQQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this)); + final List<? extends BaseQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this)); final ServerMessage message = getMessage(); if(rerouteQueues != null && rerouteQueues.size() != 0) { @@ -419,9 +427,9 @@ public class QueueEntryImpl implements QueueEntry { try { - for(AMQQueue queue : rerouteQueues) + for(BaseQueue queue : rerouteQueues) { - QueueEntry entry = queue.enqueue(message); + queue.enqueue(message); } } catch (AMQException e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index 825aa9795e..d25d73b383 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1,39 +1,51 @@ package org.apache.qpid.server.queue; -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import javax.management.JMException; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.QueueConfigType; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.QueueActor; +import org.apache.qpid.server.logging.messages.QueueMessages; +import org.apache.qpid.server.logging.subjects.QueueLogSubject; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.QueueActor; -import org.apache.qpid.server.logging.subjects.QueueLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.messages.QueueMessages; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.management.JMException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; /* * @@ -81,7 +93,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private Exchange _alternateExchange; /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ - private final ExchangeBindings _bindings = new ExchangeBindings(this); + protected final QueueEntryList _entries; @@ -102,8 +114,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicLong _totalMessagesReceived = new AtomicLong(); + private final AtomicLong _dequeueCount = new AtomicLong(); + private final AtomicLong _dequeueSize = new AtomicLong(); + private final AtomicLong _enqueueSize = new AtomicLong(); + private final AtomicLong _persistentMessageEnqueueSize = new AtomicLong(); + private final AtomicLong _persistentMessageDequeueSize = new AtomicLong(); + private final AtomicLong _persistentMessageEnqueueCount = new AtomicLong();; + private final AtomicLong _persistentMessageDequeueCount = new AtomicLong(); - + private final AtomicInteger _bindingCountHigh = new AtomicInteger(); /** max allowed size(KB) of a single message */ public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); @@ -151,18 +170,38 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicBoolean _overfull = new AtomicBoolean(false); private boolean _deleteOnNoConsumers; + private final CopyOnWriteArrayList<Binding> _bindings = new CopyOnWriteArrayList<Binding>(); + private UUID _id; + private final Map<String, Object> _arguments; + + //TODO + private long _createTime = System.currentTimeMillis(); + - protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, Map<String,Object> arguments) { - this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); + this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory(),arguments); } + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost, Map<String, Object> arguments) + { + this(queueName, durable, owner,autoDelete,virtualHost,new SimpleQueueEntryList.Factory(),arguments); + } + + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map<String, Object> arguments) + { + this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost,entryListFactory, arguments); + } + + + protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, - QueueEntryListFactory entryListFactory) + QueueEntryListFactory entryListFactory, + Map<String,Object> arguments) { if (name == null) @@ -182,6 +221,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _autoDelete = autoDelete; _virtualHost = virtualHost; _entries = entryListFactory.createQueueEntryList(this); + _arguments = arguments; + + _id = virtualHost.getConfigStore().createId(); _asyncDelivery = ReferenceCountingExecutorService.getInstance().acquireExecutorService(); @@ -208,6 +250,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener durable, !durable, priorities > 0)); + getConfigStore().addConfiguredObject(this); + try { _managedObject = new AMQQueueMBean(this); @@ -222,12 +266,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException - { - this(new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost); - } - public void resetNotifications() { // This ensure that the notification checks for the configured alerts are created. @@ -244,7 +282,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _asyncDelivery.execute(runnable); } - public AMQShortString getName() + public AMQShortString getNameShortString() { return _name; } @@ -254,6 +292,21 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _nolocal = nolocal; } + public UUID getId() + { + return _id; + } + + public QueueConfigType getConfigType() + { + return QueueConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + public boolean isDurable() { return _durable; @@ -284,7 +337,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public Map<String, Object> getArguments() { - return null; + return _arguments; } public boolean isAutoDelete() @@ -313,56 +366,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _virtualHost; } - // ------ bind and unbind - - public void bind(Exchange exchange, String bindingKey, Map<String, Object> arguments) throws AMQException - { - - FieldTable fieldTable = FieldTable.convertToFieldTable(arguments); - AMQShortString routingKey = new AMQShortString(bindingKey); - - exchange.registerQueue(routingKey, this, fieldTable); - - if (isDurable() && exchange.isDurable()) - { - - _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, fieldTable); - } - - _bindings.addBinding(routingKey, fieldTable, exchange); - } - - - public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException - { - - exchange.registerQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, arguments); - } - - _bindings.addBinding(routingKey, arguments, exchange); - } - - public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException + public String getName() { - exchange.deregisterQueue(routingKey, this, arguments); - if (isDurable() && exchange.isDurable()) - { - _virtualHost.getDurableConfigurationStore().unbindQueue(exchange, routingKey, this, arguments); - } - - boolean removed = _bindings.remove(routingKey, arguments, exchange); - if (!removed) - { - _logger.error("Mismatch between queue bindings and exchange record of bindings"); - } - } - - public List<ExchangeBinding> getExchangeBindings() - { - return new ArrayList<ExchangeBinding>(_bindings.getExchangeBindings()); + return getNameShortString().toString(); } // ------ Manage Subscriptions @@ -370,7 +376,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException { - if (isExclusiveSubscriber()) + if (hasExclusiveSubscriber()) { throw new ExistingExclusiveSubscription(); } @@ -459,17 +465,54 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteOnNoConsumers = b; } + public void addBinding(final Binding binding) + { + _bindings.add(binding); + int bindingCount = _bindings.size(); + int bindingCountHigh; + while(bindingCount > (bindingCountHigh = _bindingCountHigh.get())) + { + if(_bindingCountHigh.compareAndSet(bindingCountHigh, bindingCount)) + { + break; + } + } + } + + public int getBindingCountHigh() + { + return _bindingCountHigh.get(); + } + + public void removeBinding(final Binding binding) + { + _bindings.remove(binding); + } + + public List<Binding> getBindings() + { + return Collections.unmodifiableList(_bindings); + } + + public int getBindingCount() + { + return getBindings().size(); + } // ------ Enqueue / Dequeue + public void enqueue(ServerMessage message) throws AMQException + { + enqueue(message, null); + } - public QueueEntry enqueue(ServerMessage message) throws AMQException + public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException { incrementQueueCount(); incrementQueueSize(message); - _totalMessagesReceived.incrementAndGet(); + QueueEntry entry; Subscription exclusiveSub = _exclusiveSubscriber; @@ -554,7 +597,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _managedObject.checkForNotification(entry.getMessage()); } - return entry; + if(action != null) + { + action.onEnqueue(entry); + } + } private void deliverToSubscription(final Subscription sub, final QueueEntry entry) @@ -596,7 +643,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void incrementQueueSize(final ServerMessage message) { - getAtomicQueueSize().addAndGet(message.getSize()); + long size = message.getSize(); + getAtomicQueueSize().addAndGet(size); + _enqueueSize.addAndGet(size); + if(message.isPersistent() && isDurable()) + { + _persistentMessageEnqueueSize.addAndGet(size); + _persistentMessageEnqueueCount.incrementAndGet(); + } } private void incrementQueueCount() @@ -654,7 +708,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards - while (subscriberIter.advance()) + while (subscriberIter.advance() && entry.isAvailable()) { Subscription sub = subscriberIter.getNode().getSubscription(); @@ -702,12 +756,21 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void decrementQueueSize(final QueueEntry entry) { - getAtomicQueueSize().addAndGet(-entry.getMessage().getSize()); + final ServerMessage message = entry.getMessage(); + long size = message.getSize(); + getAtomicQueueSize().addAndGet(-size); + _dequeueSize.addAndGet(size); + if(message.isPersistent() && isDurable()) + { + _persistentMessageDequeueSize.addAndGet(size); + _persistentMessageDequeueCount.incrementAndGet(); + } } void decrementQueueCount() { getAtomicQueueCount().decrementAndGet(); + _dequeueCount.incrementAndGet(); } public boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException @@ -834,7 +897,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public int compareTo(final AMQQueue o) { - return _name.compareTo(o.getName()); + return _name.compareTo(o.getNameShortString()); } public AtomicInteger getAtomicQueueCount() @@ -847,7 +910,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _atomicQueueSize; } - private boolean isExclusiveSubscriber() + public boolean hasExclusiveSubscriber() { return _exclusiveSubscriber != null; } @@ -1099,6 +1162,45 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public void purge(final long request) + { + if(request == 0l) + { + clearQueue(); + } + else if(request > 0l) + { + + QueueEntryIterator queueListIterator = _entries.iterator(); + long count = 0; + + ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); + + while (queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + if (!node.isDeleted() && node.acquire()) + { + dequeueEntry(node, txn); + if(++count == request) + { + break; + } + } + + } + + txn.commit(); + + + } + } + + public long getCreateTime() + { + return _createTime; + } + // ------ Management functions public void deleteMessageFromTop() @@ -1172,11 +1274,21 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.add(task); } + public void removeQueueDeleteTask(final Task task) + { + _deleteTaskList.remove(task); + } + public int delete() throws AMQException { if (!_deleted.getAndSet(true)) { + for(Binding b : getBindings()) + { + _virtualHost.getBindingFactory().removeBinding(b); + } + SubscriptionList.SubscriptionNodeIterator subscriptionIter = _subscriptionList.iterator(); while (subscriptionIter.advance()) @@ -1188,8 +1300,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - _bindings.deregister(); _virtualHost.getQueueRegistry().unregisterQueue(_name); + getConfigStore().removeConfiguredObject(this); List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter() { @@ -1214,7 +1326,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for(final QueueEntry entry : entries) { adapter.setEntry(entry); - final List<AMQQueue> rerouteQueues = _alternateExchange.route(adapter); + final List<? extends BaseQueue> rerouteQueues = _alternateExchange.route(adapter); final ServerMessage message = entry.getMessage(); if(rerouteQueues != null & rerouteQueues.size() != 0) { @@ -1226,9 +1338,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { try { - for(AMQQueue queue : rerouteQueues) + for(BaseQueue queue : rerouteQueues) { - QueueEntry entry = queue.enqueue(message); + queue.enqueue(message); } } catch (AMQException e) @@ -1479,7 +1591,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // next entry they are interested in yet. This would lead to holding on to references to expired messages, etc // which would give us memory "leak". - if (!isExclusiveSubscriber()) + if (!hasExclusiveSubscriber()) { advanceAllSubscriptions(); } @@ -1820,7 +1932,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void setFlowResumeCapacity(long flowResumeCapacity) { _flowResumeCapacity = flowResumeCapacity; - + checkCapacity(); } @@ -1919,9 +2031,50 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public long getMessageDequeueCount() + { + return _dequeueCount.get(); + } + + public long getTotalEnqueueSize() + { + return _enqueueSize.get(); + } + + public long getTotalDequeueSize() + { + return _dequeueSize.get(); + } + + public long getPersistentByteEnqueues() + { + return _persistentMessageEnqueueSize.get(); + } + + public long getPersistentByteDequeues() + { + return _persistentMessageDequeueSize.get(); + } + + public long getPersistentMsgEnqueues() + { + return _persistentMessageEnqueueCount.get(); + } + + public long getPersistentMsgDequeues() + { + return _persistentMessageDequeueCount.get(); + } + + @Override public String toString() { - return String.valueOf(getName()); + return String.valueOf(getNameShortString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index d27a5ed234..8721da0f78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -61,11 +61,9 @@ public class SimpleQueueEntryList implements QueueEntryList { _deletes.incrementAndGet(); QueueEntryImpl head = _head.nextNode(); - boolean deleted = head.isDeleted(); while(head._next != null && head.isDeleted()) { - deleted = true; final QueueEntryImpl newhead = head.nextNode(); if(newhead != null) { @@ -77,11 +75,6 @@ public class SimpleQueueEntryList implements QueueEntryList head = _head.nextNode(); } - if(!deleted) - { - deleted = true; - } - if(_deletes.get() > 1000L) { _deletes.set(0L); @@ -135,7 +128,7 @@ public class SimpleQueueEntryList implements QueueEntryList public QueueEntry add(ServerMessage message) { - QueueEntryImpl node = new QueueEntryImpl(this, message); + QueueEntryImpl node = createQueueEntry(message); for (;;) { QueueEntryImpl tail = _tail; @@ -160,6 +153,11 @@ public class SimpleQueueEntryList implements QueueEntryList } } + protected QueueEntryImpl createQueueEntry(ServerMessage message) + { + return new QueueEntryImpl(this, message); + } + public QueueEntry next(QueueEntry node) { return ((QueueEntryImpl)node).getNext(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 5cb379f10d..2c4c0a0570 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -20,24 +20,33 @@ */ package org.apache.qpid.server.registry; -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; - import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; + +import org.apache.qpid.qmf.QMFService; +import org.apache.qpid.server.configuration.BrokerConfig; +import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.SystemConfig; +import org.apache.qpid.server.configuration.SystemConfigImpl; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.transport.QpidAcceptor; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * An abstract application registry that provides access to configuration information and handles the @@ -75,6 +84,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry protected RootMessageLogger _rootMessageLogger; + protected UUID _brokerId = UUID.randomUUID(); + + protected QMFService _qmfService; + + private BrokerConfig _broker; + + private ConfigStore _configStore; + static { Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownService())); @@ -100,6 +117,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _logger.info("Initialising Application Registry:" + instanceID); _instanceMap.put(instanceID, instance); + final ConfigStore store = ConfigStore.newInstance(); + store.setRoot(new SystemConfigImpl(store)); + instance.setConfigStore(store); + + BrokerConfig broker = new BrokerConfigAdapter(instance, instanceID); + + SystemConfig system = (SystemConfig) store.getRoot(); + system.addBroker(broker); + instance.setBroker(broker); + try { instance.initialise(instanceID); @@ -107,7 +134,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry catch (Exception e) { _instanceMap.remove(instanceID); - throw e; + try + { + system.removeBroker(broker); + } + finally + { + throw e; + } } } else @@ -116,6 +150,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry } } + public ConfigStore getConfigStore() + { + return _configStore; + } + + public void setConfigStore(final ConfigStore configStore) + { + _configStore = configStore; + } + public static boolean isConfigured() { return isConfigured(DEFAULT_INSTANCE); @@ -151,6 +195,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _logger.info("Shuting down ApplicationRegistry(" + instanceID + "):" + instance); } instance.close(); + instance.getBroker().getSystem().removeBroker(instance.getBroker()); } } catch (Exception e) @@ -316,5 +361,32 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { return _rootMessageLogger; } - + + public UUID getBrokerId() + { + return _brokerId; + } + + public QMFService getQMFService() + { + return _qmfService; + } + + public BrokerConfig getBroker() + { + return _broker; + } + + public void setBroker(final BrokerConfig broker) + { + _broker = broker; + } + + public VirtualHost createVirtualHost(final VirtualHostConfiguration vhostConfig) throws Exception + { + VirtualHostImpl virtualHost = new VirtualHostImpl(this, vhostConfig); + _virtualHostRegistry.registerVirtualHost(virtualHost); + getBroker().addVirtualHost(virtualHost); + return virtualHost; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java new file mode 100644 index 0000000000..c3d1945550 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java @@ -0,0 +1,163 @@ +/* + * + * 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.qpid.server.registry; + +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.common.QpidProperties; + +import java.util.UUID; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class BrokerConfigAdapter implements BrokerConfig +{ + private final IApplicationRegistry _instance; + private final int _instanceId; + private SystemConfig _system; + + private final Map<UUID, VirtualHostConfig> _vhosts = new ConcurrentHashMap<UUID, VirtualHostConfig>(); + private final long _createTime = System.currentTimeMillis(); + private UUID _id; + private String _federationTag; + + public BrokerConfigAdapter(final IApplicationRegistry instance, final int instanceID) + { + _instance = instance; + _instanceId = instanceID; + _id = instance.getConfigStore().createId(); + _federationTag = UUID.randomUUID().toString(); + } + + public void setSystem(final SystemConfig system) + { + _system = system; + } + + public SystemConfig getSystem() + { + return _system; + } + + public Integer getPort() + { + List ports = _instance.getConfiguration().getPorts(); + if(ports.size() > 0) + { + return Integer.valueOf(ports.get(0).toString()); + } + else + { + return 0; + } + } + + public Integer getWorkerThreads() + { + return _instance.getConfiguration().getProcessors(); + } + + public Integer getMaxConnections() + { + return 0; + } + + public Integer getConnectionBacklogLimit() + { + return 0; + } + + public Long getStagingThreshold() + { + return 0L; + } + + public Integer getManagementPublishInterval() + { + return 10; + } + + public String getVersion() + { + return QpidProperties.getReleaseVersion() + " [Build: " + QpidProperties.getBuildVersion() + "]"; + } + + public String getDataDirectory() + { + return _instance.getConfiguration().getQpidWork(); + } + + public void addVirtualHost(final VirtualHostConfig virtualHost) + { + virtualHost.setBroker(this); + _vhosts.put(virtualHost.getId(), virtualHost); + getConfigStore().addConfiguredObject(virtualHost); + + } + + private ConfigStore getConfigStore() + { + return _instance.getConfigStore(); + } + + public long getCreateTime() + { + return _createTime; + } + + public void createBrokerConnection(final String transport, + final String host, + final int port, + final boolean durable, + final String authMechanism, + final String username, + final String password) + { + VirtualHost vhost = _instance.getVirtualHostRegistry().getDefaultVirtualHost(); + vhost.createBrokerConnection(transport, host, port, "", durable, authMechanism, username, password); + } + + public UUID getId() + { + return _id; + } + + public BrokerConfigType getConfigType() + { + return BrokerConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return _system; + } + + public boolean isDurable() + { + return false; + } + + public String getFederationTag() + { + return _federationTag; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index f325b53dfb..e1cc1bf1dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -21,13 +21,15 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; + import org.apache.qpid.AMQException; import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.logging.RootMessageLoggerImpl; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.BrokerActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; @@ -36,7 +38,6 @@ import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; import java.io.File; @@ -51,6 +52,9 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise(int instanceID) throws Exception { + _qmfService = new QMFService(getConfigStore(), this); + + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); @@ -75,6 +79,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _databaseManager.initialiseManagement(_configuration); + _managedObjectRegistry.start(); initialiseVirtualHosts(); @@ -91,6 +96,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry try { super.close(); + _qmfService.close(); } finally { @@ -102,7 +108,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { for (String name : _configuration.getVirtualHosts()) { - _virtualHostRegistry.registerVirtualHost(new VirtualHostImpl(_configuration.getVirtualHostConfig(name))); + createVirtualHost(_configuration.getVirtualHostConfig(name)); } getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 92accb3499..f0226c7982 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -7,9 +7,9 @@ * 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 @@ -20,22 +20,25 @@ */ package org.apache.qpid.server.registry; -import java.util.Collection; -import java.net.InetSocketAddress; - -import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; + +import org.apache.qpid.qmf.QMFService; +import org.apache.qpid.server.configuration.BrokerConfig; +import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.logging.RootMessageLogger; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.transport.QpidAcceptor; -import org.apache.mina.common.IoAcceptor; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +import java.net.InetSocketAddress; +import java.util.UUID; public interface IApplicationRegistry { @@ -81,4 +84,17 @@ public interface IApplicationRegistry */ void addAcceptor(InetSocketAddress bindAddress, QpidAcceptor acceptor); + public UUID getBrokerId(); + + QMFService getQMFService(); + + void setBroker(BrokerConfig broker); + + BrokerConfig getBroker(); + + VirtualHost createVirtualHost(VirtualHostConfiguration vhostConfig) throws Exception; + + ConfigStore getConfigStore(); + + void setConfigStore(ConfigStore store); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index a299907e42..e7fc8effaf 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -42,7 +42,7 @@ public class PrincipalPermissions private static final Object CREATE_QUEUES_KEY = new Object(); private static final Object CREATE_EXCHANGES_KEY = new Object(); - + private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); @@ -64,9 +64,9 @@ public class PrincipalPermissions } /** - * + * * @param permission the type of permission to check - * + * * @param parameters vararg depending on what permission was passed in * ACCESS: none * BIND: none @@ -113,7 +113,7 @@ public class PrincipalPermissions { _fullVHostAccess = true; } - + private void grantPublish(Permission permission, Object... parameters) { Map publishRights = (Map) _permissions.get(permission); @@ -344,9 +344,9 @@ public class PrincipalPermissions } /** - * + * * @param permission the type of permission to check - * + * * @param parameters vararg depending on what permission was passed in * ACCESS: none * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey @@ -363,7 +363,7 @@ public class PrincipalPermissions switch (permission) { - case ACCESS://No Parameters + case ACCESS://No Parameters return AuthzResult.ALLOWED; // The existence of this user-specific PP infers some level of access is authorised case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey return authoriseBind(parameters); @@ -444,7 +444,7 @@ public class PrincipalPermissions { if ( new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) { - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + return (queues.size() == 0 || queues.contains(queue.getNameShortString())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } else { @@ -453,7 +453,7 @@ public class PrincipalPermissions } // If we are - return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + return (queues.size() == 0 || queues.contains(queue.getNameShortString())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } } @@ -486,7 +486,7 @@ public class PrincipalPermissions // Otherwise exchange must be listed in the white list // If the map doesn't have the exchange then it isn't allowed - if (!exchanges.containsKey(((Exchange) parameters[0]).getName())) + if (!exchanges.containsKey(((Exchange) parameters[0]).getNameShortString())) { return AuthzResult.DENIED; } @@ -494,7 +494,7 @@ public class PrincipalPermissions { // Get valid routing keys - HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName()); + HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getNameShortString()); // Having no routingKeys in the map then all are allowed. if (routingKeys == null) @@ -544,7 +544,7 @@ public class PrincipalPermissions // check the valid exchanges if (rights == null || rights.containsKey(exchangeName)) { - return AuthzResult.ALLOWED; + return AuthzResult.ALLOWED; } else { @@ -587,13 +587,13 @@ public class PrincipalPermissions // If there is a white list then check if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) { - return AuthzResult.ALLOWED; + return AuthzResult.ALLOWED; } else { return AuthzResult.DENIED; } - + } } @@ -604,7 +604,7 @@ public class PrincipalPermissions //user has been granted full access to the vhost return AuthzResult.ALLOWED; } - + Exchange exchange = (Exchange) parameters[1]; AMQQueue bind_queueName = (AMQQueue) parameters[2]; @@ -631,7 +631,7 @@ public class PrincipalPermissions } // Check to see if we have a white list of routingkeys to check - Map rkeys = (Map) exchangeDetails.get(exchange.getName()); + Map rkeys = (Map) exchangeDetails.get(exchange.getNameShortString()); // if keys is null then any rkey is allowed on this exchange if (rkeys == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java new file mode 100644 index 0000000000..4a66b74783 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java @@ -0,0 +1,39 @@ +/* + * + * 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.qpid.server.security.auth.sasl.anonymous; + +import javax.security.sasl.SaslServerFactory; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainSaslServerFactory; + +public class AnonymousInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return "ANONYMOUS"; + } + + public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration() + { + return AnonymousSaslServerFactory.class; + } +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java new file mode 100644 index 0000000000..b4cce15d88 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java @@ -0,0 +1,88 @@ +/* + * + * 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.qpid.server.security.auth.sasl.anonymous; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.mina.common.ByteBuffer; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; + +public class AnonymousSaslServer implements SaslServer +{ + public static final String MECHANISM = "ANONYMOUS"; + + private boolean _complete = false; + + public AnonymousSaslServer() + { + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + _complete = true; + return null; + } + + public boolean isComplete() + { + return _complete; + } + + public String getAuthorizationID() + { + return null; + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + throw new SaslException("Unsupported operation"); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + throw new SaslException("Unsupported operation"); + } + + public Object getNegotiatedProperty(String propName) + { + return null; + } + + public void dispose() throws SaslException + { + } +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java new file mode 100644 index 0000000000..6032255870 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java @@ -0,0 +1,63 @@ +/* + * + * 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.qpid.server.security.auth.sasl.anonymous; + +import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainSaslServer; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class AnonymousSaslServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + if (AnonymousSaslServer.MECHANISM.equals(mechanism)) + { + return new AnonymousSaslServer(); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE) || + props.containsKey(Sasl.POLICY_NOANONYMOUS)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + else + { + return new String[]{AnonymousSaslServer.MECHANISM}; + } + } +}
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index 5ca75aa9ae..31211d6b9e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -20,22 +20,24 @@ */ package org.apache.qpid.server.store; +import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.TransactionLogMessages; -import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.commons.configuration.Configuration; - import java.io.ByteArrayInputStream; import java.io.File; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; import java.sql.Blob; import java.sql.Connection; import java.sql.Driver; @@ -49,8 +51,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; public class DerbyMessageStore implements MessageStore @@ -590,7 +590,10 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString()); + stmt.execute(); + stmt.close(); + conn.commit(); ResultSet rs = stmt.executeQuery(); @@ -617,7 +620,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing Exchange with name " + exchange.getName() + " to database: " + e, e); + throw new AMQException("Error writing Exchange with name " + exchange.getNameShortString() + " to database: " + e, e); } } @@ -631,11 +634,11 @@ public class DerbyMessageStore implements MessageStore { conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_EXCHANGE); - stmt.setString(1, exchange.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString()); int results = stmt.executeUpdate(); if(results == 0) { - throw new AMQException("Exchange " + exchange.getName() + " not found"); + throw new AMQException("Exchange " + exchange.getNameShortString() + " not found"); } else { @@ -645,7 +648,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing deleting with name " + exchange.getName() + " from database: " + e, e); + throw new AMQException("Error writing deleting with name " + exchange.getNameShortString() + " from database: " + e, e); } finally { @@ -677,8 +680,8 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_BINDING); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); ResultSet rs = stmt.executeQuery(); @@ -687,8 +690,8 @@ public class DerbyMessageStore implements MessageStore if (!rs.next()) { stmt = conn.prepareStatement(INSERT_INTO_BINDINGS); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); if(args != null) { @@ -713,8 +716,8 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing binding for AMQQueue with name " + queue.getName() + " to exchange " - + exchange.getName() + " to database: " + e, e); + throw new AMQException("Error writing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " to database: " + e, e); } finally { @@ -748,23 +751,23 @@ public class DerbyMessageStore implements MessageStore conn = newConnection(); // exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS); - stmt.setString(1, exchange.getName().toString() ); - stmt.setString(2, queue.getName().toString()); + stmt.setString(1, exchange.getNameShortString().toString() ); + stmt.setString(2, queue.getNameShortString().toString()); stmt.setString(3, routingKey == null ? null : routingKey.toString()); if(stmt.executeUpdate() != 1) { - throw new AMQException("Queue binding for queue with name " + queue.getName() + " to exchange " - + exchange.getName() + " not found"); + throw new AMQException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " not found"); } conn.commit(); stmt.close(); } catch (SQLException e) { - throw new AMQException("Error removing binding for AMQQueue with name " + queue.getName() + " to exchange " - + exchange.getName() + " in database: " + e, e); + throw new AMQException("Error removing binding for AMQQueue with name " + queue.getNameShortString() + " to exchange " + + exchange.getNameShortString() + " in database: " + e, e); } finally { @@ -801,7 +804,7 @@ public class DerbyMessageStore implements MessageStore Connection conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(FIND_QUEUE); - stmt.setString(1, queue.getName().toString()); + stmt.setString(1, queue.getNameShortString().toString()); ResultSet rs = stmt.executeQuery(); @@ -816,7 +819,7 @@ public class DerbyMessageStore implements MessageStore ? null : queue.getPrincipalHolder().getPrincipal().getName(); - stmt.setString(1, queue.getName().toString()); + stmt.setString(1, queue.getNameShortString().toString()); stmt.setString(2, owner); stmt.execute(); @@ -830,7 +833,7 @@ public class DerbyMessageStore implements MessageStore } catch (SQLException e) { - throw new AMQException("Error writing AMQQueue with name " + queue.getName() + " to database: " + e, e); + throw new AMQException("Error writing AMQQueue with name " + queue.getNameShortString() + " to database: " + e, e); } } } @@ -843,7 +846,7 @@ public class DerbyMessageStore implements MessageStore public void removeQueue(final AMQQueue queue) throws AMQException { - AMQShortString name = queue.getName(); + AMQShortString name = queue.getNameShortString(); _logger.debug("public void removeQueue(AMQShortString name = " + name + "): called"); Connection conn = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java index cfbacd28c8..a50e8e99b4 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -31,6 +31,11 @@ import org.apache.commons.configuration.Configuration; public interface DurableConfigurationStore { + public static interface Source + { + DurableConfigurationStore getDurableConfigurationStore(); + } + /** * Called after instantiation in order to configure the message store. A particular implementation can define * whatever parameters it wants. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 684d3c2e74..b0ea0ef506 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -20,41 +20,49 @@ */ package org.apache.qpid.server.subscription; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.ConcurrentHashMap; -import java.util.Map; - import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SubscriptionConfig; +import org.apache.qpid.server.configuration.SubscriptionConfigType; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.SubscriptionActor; import org.apache.qpid.server.logging.messages.SubscriptionMessages; import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.filter.FilterManager; -import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * Encapsulation of a supscription to a queue. <p/> Ties together the protocol session of a subscriber, the consumer tag * that was given out by the broker and the channel id. <p/> */ -public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener +public abstract class SubscriptionImpl implements Subscription, FlowCreditManager.FlowCreditManagerListener, + SubscriptionConfig { private StateListener _stateListener = new StateListener() @@ -85,6 +93,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final long _subscriptionID = idGenerator.getAndIncrement(); private LogSubject _logSubject; private LogActor _logActor; + private UUID _id; static final class BrowserSubscription extends SubscriptionImpl @@ -152,6 +161,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return false; } + @Override + public boolean isExplicitAcknowledge() + { + return false; + } + /** * This method can be called by each of the publisher threads. As a result all changes to the channel object must be * thread safe. @@ -318,9 +333,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _autoClose = false; } - } + public ConfigStore getConfigStore() + { + return getQueue().getConfigStore(); + } public synchronized void setQueue(AMQQueue queue, boolean exclusive) @@ -331,6 +349,9 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } _queue = queue; + _id = getConfigStore().createId(); + getConfigStore().addConfiguredObject(this); + _logSubject = new SubscriptionLogSubject(this); _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); @@ -414,7 +435,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public boolean hasInterest(QueueEntry entry) { - + //check that the message hasn't been rejected @@ -505,7 +526,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage { _stateChangeLock.unlock(); } - + getConfigStore().removeConfiguredObject(this); //Log Subscription closed CurrentActor.get().message(_logSubject, SubscriptionMessages.SUB_CLOSE()); @@ -689,4 +710,60 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } abstract boolean isBrowser(); + + public String getCreditMode() + { + return "WINDOW"; + } + + public SessionConfig getSessionConfig() + { + return getChannel(); + } + + public boolean isBrowsing() + { + return isBrowser(); + } + + public boolean isExplicitAcknowledge() + { + return true; + } + + public UUID getId() + { + return _id; + } + + public boolean isDurable() + { + return false; + } + + public SubscriptionConfigType getConfigType() + { + return SubscriptionConfigType.getInstance(); + } + + public boolean isExclusive() + { + return getQueue().hasExclusiveSubscriber(); + } + + public ConfiguredObject getParent() + { + return getSessionConfig(); + } + + public String getName() + { + return String.valueOf(_consumerTag); + } + + public Map<String, Object> getArguments() + { + return null; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 5b3668ab64..54c294c76d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -36,11 +36,12 @@ import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.configuration.*; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderProperties; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.AMQException; import org.apache.qpid.transport.*; @@ -50,12 +51,10 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.ConcurrentHashMap; -import java.util.ArrayList; -import java.util.Map; -import java.util.HashMap; +import java.util.*; import java.nio.ByteBuffer; -public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener +public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener, SubscriptionConfig { private static final AtomicLong idGenerator = new AtomicLong(0); @@ -98,6 +97,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private LogSubject _logSubject; private LogActor _logActor; private Map<String, Object> _properties = new ConcurrentHashMap<String, Object>(); + private UUID _id; + private String _traceExclude; + private String _trace; public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode, @@ -116,7 +118,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _creditManager.addStateListener(this); _state.set(_creditManager.hasCredit() ? State.ACTIVE : State.SUSPENDED); - } public void setNoLocal(boolean noLocal) @@ -146,6 +147,11 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); } _queue = queue; + Map<String, Object> arguments = queue.getArguments() == null ? Collections.EMPTY_MAP : queue.getArguments(); + _traceExclude = (String) arguments.get("qpid.trace.exclude"); + _trace = (String) arguments.get("qpid.trace.id"); + _id = getConfigStore().createId(); + getConfigStore().addConfiguredObject(this); _logSubject = new SubscriptionLogSubject(this); _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); @@ -235,6 +241,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } } _creditManager.removeListener(this); + getConfigStore().removeConfiguredObject(this); } finally { @@ -245,6 +252,11 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } + public ConfigStore getConfigStore() + { + return getQueue().getConfigStore(); + } + public void creditStateChanged(boolean hasCredit) { @@ -290,6 +302,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr MessageTransfer xfr; + DeliveryProperties deliveryProps; + MessageProperties messageProps = null; + if(serverMsg instanceof MessageTransferMessage) { @@ -316,11 +331,15 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } else { + if(header instanceof MessageProperties) + { + messageProps = (MessageProperties) header; + } newHeaders.add(header); } } - DeliveryProperties deliveryProps = new DeliveryProperties(); + deliveryProps = new DeliveryProperties(); if(origDeliveryProps != null) { if(origDeliveryProps.hasDeliveryMode()) @@ -343,21 +362,33 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { deliveryProps.setRoutingKey(origDeliveryProps.getRoutingKey()); } + if(origDeliveryProps.hasTimestamp()) + { + deliveryProps.setTimestamp(origDeliveryProps.getTimestamp()); + } + } deliveryProps.setRedelivered(entry.isRedelivered()); newHeaders.add(deliveryProps); + + if(_trace != null && messageProps == null) + { + messageProps = new MessageProperties(); + newHeaders.add(messageProps); + } + Header header = new Header(newHeaders); xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody()); } - else + else if(serverMsg instanceof AMQMessage) { AMQMessage message_0_8 = (AMQMessage) serverMsg; - DeliveryProperties deliveryProps = new DeliveryProperties(); - MessageProperties messageProps = new MessageProperties(); + deliveryProps = new DeliveryProperties(); + messageProps = new MessageProperties(); int size = (int) message_0_8.getSize(); ByteBuffer body = ByteBuffer.allocate(size); @@ -399,9 +430,52 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr messageProps.setUserId(properties.getUserId().getBytes()); } + FieldTable fieldTable = properties.getHeaders(); + + final Map<String, Object> appHeaders = FieldTable.convertToMap(fieldTable); + + + messageProps.setApplicationHeaders(appHeaders); + + Header header = new Header(headers); + xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); + } + else + { + + deliveryProps = new DeliveryProperties(); + messageProps = new MessageProperties(); + + int size = (int) serverMsg.getSize(); + ByteBuffer body = ByteBuffer.allocate(size); + serverMsg.getContent(body, 0); + body.flip(); + + Struct[] headers = new Struct[] { deliveryProps, messageProps }; + + + deliveryProps.setExpiration(serverMsg.getExpiration()); + deliveryProps.setImmediate(serverMsg.isImmediate()); + deliveryProps.setPriority(MessageDeliveryPriority.get(serverMsg.getMessageHeader().getPriority())); + deliveryProps.setRedelivered(entry.isRedelivered()); + deliveryProps.setRoutingKey(serverMsg.getRoutingKey()); + deliveryProps.setTimestamp(serverMsg.getMessageHeader().getTimestamp()); + + messageProps.setContentEncoding(serverMsg.getMessageHeader().getEncoding()); + messageProps.setContentLength(size); + messageProps.setContentType(serverMsg.getMessageHeader().getMimeType()); + if(serverMsg.getMessageHeader().getCorrelationId() != null) + { + messageProps.setCorrelationId(serverMsg.getMessageHeader().getCorrelationId().getBytes()); + } + + + // TODO - ReplyTo + + final Map<String, Object> appHeaders = new HashMap<String, Object>(); - properties.getHeaders().processOverElements( + /*properties.getHeaders().processOverElements( new FieldTable.FieldTableElementProcessor() { @@ -424,39 +498,98 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr messageProps.setApplicationHeaders(appHeaders); - +*/ Header header = new Header(headers); xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); } - if(_acceptMode == MessageAcceptMode.NONE) + boolean excludeDueToFederation = false; + + if(_trace != null) { - xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); + if(!messageProps.hasApplicationHeaders()) + { + messageProps.setApplicationHeaders(new HashMap<String,Object>()); + } + Map<String,Object> appHeaders = messageProps.getApplicationHeaders(); + String trace = (String) appHeaders.get("x-qpid.trace"); + if(trace == null) + { + trace = _trace; + } + else + { + if(_traceExclude != null) + { + excludeDueToFederation = Arrays.asList(trace.split(",")).contains(_traceExclude); + } + trace+=","+_trace; + } + appHeaders.put("x-qpid.trace",trace); } - else if(_flowMode == MessageFlowMode.WINDOW) + + if(!excludeDueToFederation) { - xfr.setCompletionListener(new Method.CompletionListener() - { - public void onComplete(Method method) + if(_acceptMode == MessageAcceptMode.NONE) + { + xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); + } + else if(_flowMode == MessageFlowMode.WINDOW) + { + xfr.setCompletionListener(new Method.CompletionListener() { - restoreCredit(entry); - } - }); - } + public void onComplete(Method method) + { + restoreCredit(entry); + } + }); + } - _postIdSettingAction._xfr = xfr; - if(_acceptMode == MessageAcceptMode.EXPLICIT) - { - _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); + _postIdSettingAction._xfr = xfr; + if(_acceptMode == MessageAcceptMode.EXPLICIT) + { + _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); + } + else + { + _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); + } + + _session.sendMessage(xfr, _postIdSettingAction); + + if(_acceptMode == MessageAcceptMode.NONE && _acquireMode == MessageAcquireMode.PRE_ACQUIRED) + { + forceDequeue(entry, false); + } } else { - _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); + forceDequeue(entry, _flowMode == MessageFlowMode.WINDOW); + } + } + + private void forceDequeue(final QueueEntry entry, final boolean restoreCredit) + { + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + txn.dequeue(entry.getQueue(),entry.getMessage(), + new ServerTransaction.Action() + { + public void postCommit() + { + if(restoreCredit) + { + restoreCredit(entry); + } + entry.discard(); + } - _session.sendMessage(xfr, _postIdSettingAction); + public void onRollback() + { + } + }); } void reject(QueueEntry entry) @@ -660,4 +793,59 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } + public SessionConfig getSessionConfig() + { + return getSession(); + } + + public boolean isBrowsing() + { + return _acquireMode == MessageAcquireMode.NOT_ACQUIRED; + } + + public boolean isExclusive() + { + return getQueue().hasExclusiveSubscriber(); + } + + public ConfiguredObject getParent() + { + return getSessionConfig(); + } + + public boolean isDurable() + { + return false; + } + + public SubscriptionConfigType getConfigType() + { + return SubscriptionConfigType.getInstance(); + } + + public boolean isExplicitAcknowledge() + { + return _acceptMode == MessageAcceptMode.EXPLICIT; + } + + public String getCreditMode() + { + return _flowMode.toString(); + } + + public UUID getId() + { + return _id; + } + + public String getName() + { + return _destination; + } + + public Map<String, Object> getArguments() + { + //TODO + return Collections.EMPTY_MAP; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 2a8b99ddac..1aff1eec86 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -20,12 +20,20 @@ */ package org.apache.qpid.server.transport; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.Connection; import org.apache.qpid.transport.Method; -import org.apache.qpid.server.virtualhost.VirtualHost; public class ServerConnection extends Connection { + private ConnectionConfig _config; + private Runnable _onOpenTask; + + public ServerConnection() + { + } + @Override protected void invoke(Method method) { @@ -36,6 +44,10 @@ public class ServerConnection extends Connection protected void setState(State state) { super.setState(state); + if(state == State.OPEN && _onOpenTask != null) + { + _onOpenTask.run(); + } } @Override @@ -61,4 +73,19 @@ public class ServerConnection extends Connection { _virtualHost = virtualHost; } + + public void setConnectionConfig(final ConnectionConfig config) + { + _config = config; + } + + public ConnectionConfig getConfig() + { + return _config; + } + + public void onOpen(final Runnable task) + { + _onOpenTask = task; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index cfc5bb3a72..4cfcafa533 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -40,7 +40,7 @@ public class ServerConnectionDelegate extends ServerDelegate public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN) { - this(Collections.EMPTY_MAP, Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); + this(new HashMap<String,Object>(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 77dfbc0376..3e48ac2619 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -20,32 +20,55 @@ */ package org.apache.qpid.server.transport; -import org.apache.qpid.transport.*; +import com.sun.security.auth.UserPrincipal; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; +import org.apache.qpid.server.configuration.ConnectionConfig; +import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.SessionConfigType; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.subscription.Subscription_0_10; -import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.AMQException; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.Binary; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.Range; +import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDelegate; +import static org.apache.qpid.util.Serial.gt; -import java.util.*; +import java.lang.ref.WeakReference; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.security.Principal; -import java.lang.ref.WeakReference; -import static org.apache.qpid.util.Serial.*; -import com.sun.security.auth.UserPrincipal; - -public class ServerSession extends Session implements PrincipalHolder +public class ServerSession extends Session implements PrincipalHolder, SessionConfig { private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); + private final UUID _id; + private ConnectionConfig _connectionConfig; + public static interface MessageDispositionChangeListener { public void onAccept(); @@ -78,37 +101,41 @@ public class ServerSession extends Session implements PrincipalHolder private final WeakReference<Session> _reference; - - ServerSession(Connection connection, Binary name, long expiry) + ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) { - super(connection, name, expiry); - - _transaction = new AutoCommitTransaction(this.getMessageStore()); - _principal = new UserPrincipal(connection.getAuthorizationID()); - _reference = new WeakReference(this); + this(connection, delegate, name, expiry, ((ServerConnection)connection).getConfig()); } - ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) + public ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry, ConnectionConfig connConfig) { super(connection, delegate, name, expiry); + _connectionConfig = connConfig; _transaction = new AutoCommitTransaction(this.getMessageStore()); _principal = new UserPrincipal(connection.getAuthorizationID()); _reference = new WeakReference(this); + _id = getConfigStore().createId(); + getConfigStore().addConfiguredObject(this); + } + + private ConfigStore getConfigStore() + { + return getConnectionConfig().getConfigStore(); } + @Override protected boolean isFull(int id) { return isCommandsFull(id); } - public void enqueue(final ServerMessage message, final ArrayList<AMQQueue> queues) + public void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues) { _transaction.enqueue(queues,message, new ServerTransaction.Action() { - AMQQueue[] _queues = queues.toArray(new AMQQueue[queues.size()]); + BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]); public void postCommit() { @@ -243,7 +270,7 @@ public class ServerSession extends Session implements PrincipalHolder Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); Iterator<Range> rangeIter = ranges.iterator(); - if(rangeIter.hasNext()) + if(rangeIter.hasNext()) { Range range = rangeIter.next(); @@ -290,6 +317,8 @@ public class ServerSession extends Session implements PrincipalHolder } _messageDispositionListenerMap.clear(); + getConfigStore().removeConfiguredObject(this); + for (Task task : _taskList) { task.doTask(this); @@ -391,8 +420,61 @@ public class ServerSession extends Session implements PrincipalHolder public MessageStore getMessageStore() { - return ((ServerConnection)getConnection()).getVirtualHost().getMessageStore(); + return getVirtualHost().getMessageStore(); } + public VirtualHost getVirtualHost() + { + return (VirtualHost) _connectionConfig.getVirtualHost(); + } + + public UUID getId() + { + return _id; + } + + public SessionConfigType getConfigType() + { + return SessionConfigType.getInstance(); + } + public ConfiguredObject getParent() + { + return getVirtualHost(); + } + + public boolean isDurable() + { + return false; + } + + public boolean isAttached() + { + return true; + } + + public long getDetachedLifespan() + { + return 0; + } + + public Long getExpiryTime() + { + return null; + } + + public Long getMaxClientRate() + { + return null; + } + + public ConnectionConfig getConnectionConfig() + { + return _connectionConfig; + } + + public String getSessionName() + { + return getName().toString(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 4ade799c59..3b0f990377 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -28,6 +28,7 @@ import org.apache.qpid.server.exchange.*; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.message.MessageTransferMessage; import org.apache.qpid.server.message.MessageMetaData_0_10; import org.apache.qpid.server.subscription.Subscription_0_10; @@ -42,6 +43,7 @@ import org.apache.qpid.framing.*; import java.util.ArrayList; import java.util.Collection; import java.util.Map; +import java.nio.ByteBuffer; public class ServerSessionDelegate extends SessionDelegate { @@ -218,11 +220,15 @@ public class ServerSessionDelegate extends SessionDelegate MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); final MessageStore store = getVirtualHost(ssn).getMessageStore(); StoredMessage<MessageMetaData_0_10> storeMessage = store.addMessage(messageMetaData); - storeMessage.addContent(0,xfr.getBody()); + ByteBuffer body = xfr.getBody(); + if(body != null) + { + storeMessage.addContent(0, body); + } storeMessage.flushToStore(); MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference()); - ArrayList<AMQQueue> queues = exchange.route(message); + ArrayList<? extends BaseQueue> queues = exchange.route(message); @@ -355,7 +361,7 @@ public class ServerSessionDelegate extends SessionDelegate else { // TODO - check exchange has same properties - if(!exchange.getType().toString().equals(method.getType())) + if(!exchange.getTypeShortString().toString().equals(method.getType())) { exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); } @@ -419,7 +425,7 @@ public class ServerSessionDelegate extends SessionDelegate } else { - if(!exchange.getType().toString().equals(method.getType())) + if(!exchange.getTypeShortString().toString().equals(method.getType())) { exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); } @@ -525,7 +531,7 @@ public class ServerSessionDelegate extends SessionDelegate if(exchange != null) { result.setDurable(exchange.isDurable()); - result.setType(exchange.getType().toString()); + result.setType(exchange.getTypeShortString().toString()); result.setNotFound(false); } else @@ -582,30 +588,23 @@ public class ServerSessionDelegate extends SessionDelegate + "' to Queue: '" + method.getQueue() + "' not allowed"); } - else if(exchange.getType().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) + else if(exchange.getTypeShortString().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) { exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header"); } else { - try - { - AMQShortString routingKey = new AMQShortString(method.getBindingKey()); - FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments()); + AMQShortString routingKey = new AMQShortString(method.getBindingKey()); + FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments()); - if (!exchange.isBound(routingKey, fieldTable, queue)) - { - queue.bind(exchange, routingKey, fieldTable); + if (!exchange.isBound(routingKey, fieldTable, queue)) + { + virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); - } - else - { - // todo - } } - catch (AMQException e) + else { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + // todo } } @@ -649,14 +648,7 @@ public class ServerSessionDelegate extends SessionDelegate } else { - try - { - queue.unBind(exchange, new AMQShortString(method.getBindingKey()), null); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } + virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); } } @@ -827,7 +819,7 @@ public class ServerSessionDelegate extends SessionDelegate { queue.setDeleteOnNoConsumers(true); } - + final String alternateExchangeName = method.getAlternateExchange(); if(alternateExchangeName != null && alternateExchangeName.length() != 0) { @@ -870,11 +862,12 @@ public class ServerSessionDelegate extends SessionDelegate if (autoRegister) { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); - queue.bind(defaultExchange, new AMQShortString(queueName), null); + virtualHost.getBindingFactory().addBinding(queueName, queue, defaultExchange, null); } @@ -1114,7 +1107,7 @@ public class ServerSessionDelegate extends SessionDelegate if(queue != null) { - result.setQueue(queue.getName().toString()); + result.setQueue(queue.getNameShortString().toString()); result.setDurable(queue.isDurable()); result.setExclusive(queue.isExclusive()); result.setAutoDelete(queue.isAutoDelete()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java index 7b29106ba6..f674741057 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.txn; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.store.TransactionLog; @@ -46,7 +47,7 @@ public class AutoCommitTransaction implements ServerTransaction postCommitAction.postCommit(); } - public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { try @@ -105,7 +106,7 @@ public class AutoCommitTransaction implements ServerTransaction } - public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { try { @@ -128,7 +129,7 @@ public class AutoCommitTransaction implements ServerTransaction } - public void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction) + public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postCommitAction) { try { @@ -137,7 +138,7 @@ public class AutoCommitTransaction implements ServerTransaction { TransactionLog.Transaction txn = _transactionLog.newTransaction(); Long id = message.getMessageNumber(); - for(AMQQueue q : queues) + for(BaseQueue q : queues) { if(q.isDurable()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index 9997fbe767..1124b0e812 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -2,6 +2,7 @@ package org.apache.qpid.server.txn; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.store.TransactionLog; @@ -28,7 +29,7 @@ public class LocalTransaction implements ServerTransaction _postCommitActions.add(postCommitAction); } - public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { if(message.isPersistent() && queue.isDurable()) { @@ -113,7 +114,7 @@ public class LocalTransaction implements ServerTransaction } } - public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + public void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction) { if(message.isPersistent() && queue.isDurable()) { @@ -132,7 +133,7 @@ public class LocalTransaction implements ServerTransaction } - public void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction) + public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postCommitAction) { @@ -140,7 +141,7 @@ public class LocalTransaction implements ServerTransaction { if(_transaction == null) { - for(AMQQueue queue : queues) + for(BaseQueue queue : queues) { if(queue.isDurable()) { @@ -155,7 +156,7 @@ public class LocalTransaction implements ServerTransaction try { - for(AMQQueue queue : queues) + for(BaseQueue queue : queues) { if(queue.isDurable()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java index 88bdc363c4..f3ef6569f3 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -20,15 +20,12 @@ */ package org.apache.qpid.server.txn; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.EnqueableMessage; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.QueueEntry; -import java.util.List; -import java.util.SortedSet; import java.util.Collection; +import java.util.List; public interface ServerTransaction { @@ -45,13 +42,13 @@ public interface ServerTransaction public void onRollback(); } - void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + void dequeue(BaseQueue queue, EnqueableMessage message, Action postCommitAction); void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction); - void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + void enqueue(BaseQueue queue, EnqueableMessage message, Action postCommitAction); - void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction); + void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postCommitAction); void commit(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e4a382d275..c140e4a144 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -21,7 +21,10 @@ package org.apache.qpid.server.virtualhost; import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfig; +import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; @@ -31,8 +34,13 @@ import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.binding.BindingFactory; -public interface VirtualHost +import java.util.UUID; +import java.util.TimerTask; + +public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig { IConnectionRegistry getConnectionRegistry(); @@ -59,4 +67,24 @@ public interface VirtualHost void close() throws Exception; ManagedObject getManagedObject(); + + UUID getBrokerId(); + + void scheduleTask(long period, TimerTask task); + + + IApplicationRegistry getApplicationRegistry(); + + BindingFactory getBindingFactory(); + + void createBrokerConnection(String transport, + String host, + int port, + String vhost, + boolean durable, + String authMechanism, String username, String password); + + ConfigStore getConfigStore(); + + void removeBrokerConnection(BrokerLink brokerLink); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index c543531210..221ec0b639 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -34,10 +34,10 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.TransactionLogMessages; -import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; @@ -215,7 +215,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (queue == null) { _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " - + exchange.getName()); + + exchange.getNameShortString()); } else { @@ -227,10 +227,18 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa argumentsFT = new FieldTable(org.apache.mina.common.ByteBuffer.wrap(buf),buf.limit()); } - _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName - + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")"); + BindingFactory bf = _virtualHost.getBindingFactory(); - queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); + Map<String, Object> argumentMap = FieldTable.convertToMap(argumentsFT); + + if(bf.getBinding(bindingKey, queue, exchange, argumentMap) == null) + { + + _logger.info("Restoring binding: (Exchange: " + exchange.getNameShortString() + ", Queue: " + queueName + + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")"); + + bf.restoreBinding(bindingKey, queue, exchange, argumentMap); + } } } @@ -271,7 +279,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (_logger.isDebugEnabled()) { - _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getName()); + _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getNameShortString()); } Integer count = _queueRecoveries.get(queueName); @@ -286,7 +294,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa } else { - _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getName() + " is unknwon, entry will be discarded"); + _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getNameShortString() + " is unknwon, entry will be discarded"); TransactionLog.Transaction txn = _transactionLog.newTransaction(); txn.dequeueMessage(queue, messageId); txn.commitTranAsync(); @@ -333,7 +341,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1005(entry.getValue(), entry.getKey())); CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(entry.getKey(), true)); - } + } CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(null, false)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 2f1528eb43..b208872a5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -20,19 +20,21 @@ */ package org.apache.qpid.server.virtualhost; -import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.VirtualHostMessages; -import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; -import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.binding.BindingFactory; +import org.apache.qpid.server.configuration.BrokerConfig; +import org.apache.qpid.server.configuration.ConfigStore; +import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.ExchangeConfiguration; import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfigType; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; @@ -41,6 +43,11 @@ import org.apache.qpid.server.exchange.DefaultExchangeRegistry; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.federation.BrokerLink; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.VirtualHostMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.queue.AMQQueue; @@ -48,14 +55,15 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.Accessable; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import javax.management.NotCompliantMBeanException; import java.util.Collections; @@ -63,6 +71,9 @@ import java.util.LinkedList; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + public class VirtualHostImpl implements Accessable, VirtualHost { @@ -88,9 +99,17 @@ public class VirtualHostImpl implements Accessable, VirtualHost private ACLManager _accessManager; - private final Timer _houseKeepingTimer; + private final Timer _timer; + private final IApplicationRegistry _appRegistry; private VirtualHostConfiguration _configuration; private DurableConfigurationStore _durableConfigurationStore; + private BindingFactory _bindingFactory; + private BrokerConfig _broker; + private UUID _id; + + + private final long _createTime = System.currentTimeMillis(); + private final ConcurrentHashMap<BrokerLink,BrokerLink> _links = new ConcurrentHashMap<BrokerLink, BrokerLink>(); public void setAccessableName(String name) { @@ -113,6 +132,26 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _configuration; } + public UUID getId() + { + return _id; //To change body of implemented methods use File | Settings | File Templates. + } + + public VirtualHostConfigType getConfigType() + { + return VirtualHostConfigType.getInstance(); + } + + public ConfiguredObject getParent() + { + return getBroker(); + } + + public boolean isDurable() + { + return false; + } + /** * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any * implementaion of an Exchange MBean should extend this class. @@ -141,23 +180,28 @@ public class VirtualHostImpl implements Accessable, VirtualHost } // End of MBean class - /** - * Normal Constructor - * - * @param hostConfig - * - * @throws Exception - */ - public VirtualHostImpl(VirtualHostConfiguration hostConfig) throws Exception + + + public VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig) throws Exception { - this(hostConfig, null); + this(appRegistry, hostConfig, null); } + public VirtualHostImpl(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception { + this(ApplicationRegistry.getInstance(),hostConfig,store); + } + + private VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig, MessageStore store) throws Exception + { + _appRegistry = appRegistry; + _broker = appRegistry.getBroker(); _configuration = hostConfig; _name = hostConfig.getName(); + _id = appRegistry.getConfigStore().createId(); + CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name)); if (_name == null || _name.length() == 0) @@ -169,7 +213,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _connectionRegistry = new ConnectionRegistry(this); - _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); + _timer = new Timer("TimerThread-" + _name + ":", true); _queueRegistry = new DefaultQueueRegistry(this); @@ -178,6 +222,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _exchangeRegistry = new DefaultExchangeRegistry(this); + //Create a temporary RT to store the durable entries from the config file // so we can replay them in to the real _RT after it has been loaded. /// This should be removed after the _RT has been fully split from the the TL @@ -189,6 +234,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost // This needs to be after the RT has been defined as it creates the default durable exchanges. _exchangeRegistry.initialise(); + _bindingFactory = new BindingFactory(this); + initialiseModel(hostConfig); if (store != null) @@ -205,9 +252,11 @@ public class VirtualHostImpl implements Accessable, VirtualHost initialiseMessageStore(hostConfig); } + + //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config // file and write them in to the new routing Table. - for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) +/* for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) { getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments); } @@ -220,7 +269,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) { getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - } + }*/ _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); @@ -250,7 +299,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost } catch (Exception e) { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + _logger.error("Exception in housekeeping for queue: " + q.getNameShortString().toString(), e); //Don't throw exceptions as this will stop the // house keeping task from running. } @@ -258,9 +307,8 @@ public class VirtualHostImpl implements Accessable, VirtualHost } } - _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period / 2, - period); + final TimerTask expiredMessagesTask = new RemoveExpiredMessagesTask(); + scheduleTask(period, expiredMessagesTask); class ForceChannelClosuresTask extends TimerTask { @@ -272,6 +320,12 @@ public class VirtualHostImpl implements Accessable, VirtualHost } } + public void scheduleTask(final long period, final TimerTask task) + { + _timer.scheduleAtFixedRate(task, period / 2, period); + } + + private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception { String messageStoreClass = hostConfig.getMessageStoreClass(); @@ -377,7 +431,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost List routingKeys = queueConfiguration.getRoutingKeys(); if (routingKeys == null || routingKeys.isEmpty()) { - routingKeys = Collections.singletonList(queue.getName()); + routingKeys = Collections.singletonList(queue.getNameShortString()); } for (Object routingKeyNameObj : routingKeys) @@ -387,12 +441,12 @@ public class VirtualHostImpl implements Accessable, VirtualHost { _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); } - queue.bind(exchange, routingKey, null); + _bindingFactory.addBinding(routingKey.toString(), queue, exchange, null); } if (exchange != _exchangeRegistry.getDefaultExchange()) { - queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); + _bindingFactory.addBinding(queue.getNameShortString().toString(), queue, exchange, null); } } @@ -401,6 +455,26 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _name; } + public BrokerConfig getBroker() + { + return _broker; + } + + public String getFederationTag() + { + return _broker.getFederationTag(); + } + + public void setBroker(final BrokerConfig broker) + { + _broker = broker; + } + + public long getCreateTime() + { + return _createTime; + } + public QueueRegistry getQueueRegistry() { return _queueRegistry; @@ -457,9 +531,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost } //Stop Housekeeping - if (_houseKeepingTimer != null) + if (_timer != null) { - _houseKeepingTimer.cancel(); + _timer.cancel(); } //Close MessageStore @@ -481,6 +555,59 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _virtualHostMBean; } + public UUID getBrokerId() + { + return _appRegistry.getBrokerId(); + } + + public IApplicationRegistry getApplicationRegistry() + { + return _appRegistry; + } + + public BindingFactory getBindingFactory() + { + return _bindingFactory; + } + + public void createBrokerConnection(final String transport, + final String host, + final int port, + final String vhost, + final boolean durable, + final String authMechanism, + final String username, + final String password) + { + BrokerLink blink = new BrokerLink(this, transport, host, port, vhost, durable, authMechanism, username, password); + _links.putIfAbsent(blink,blink); + getConfigStore().addConfiguredObject(blink); + } + + public void removeBrokerConnection(final String transport, + final String host, + final int port, + final String vhost) + { + removeBrokerConnection(new BrokerLink(this, transport, host, port, vhost, false, null,null,null)); + + } + + public void removeBrokerConnection(BrokerLink blink) + { + blink = _links.get(blink); + if(blink != null) + { + blink.close(); + getConfigStore().removeConfiguredObject(blink); + } + } + + public ConfigStore getConfigStore() + { + return getApplicationRegistry().getConfigStore(); + } + /** * Temporary Startup RT class to record the creation of persistent queues / exchanges. * diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index b86e0d0baf..5975eeec3d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.virtualhost;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.configuration.ConfigStore;
import java.util.ArrayList;
import java.util.Collection;
@@ -52,7 +53,7 @@ public class VirtualHostRegistry public VirtualHost getVirtualHost(String name)
{
- if(name == null || name.trim().length() == 0 )
+ if(name == null || name.trim().length() == 0 || "/".equals(name.trim()))
{
name = getDefaultVirtualHostName();
}
@@ -60,6 +61,11 @@ public class VirtualHostRegistry return _registry.get(name);
}
+ public VirtualHost getDefaultVirtualHost()
+ {
+ return getVirtualHost(getDefaultVirtualHostName());
+ }
+
private String getDefaultVirtualHostName()
{
return _defaultVirtualHostName;
@@ -80,4 +86,9 @@ public class VirtualHostRegistry {
return _applicationRegistry;
}
+
+ public ConfigStore getConfigStore()
+ {
+ return _applicationRegistry.getConfigStore();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java index faa7b85d58..f26611f0bc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java @@ -219,7 +219,7 @@ public class MessageStoreTool _console.println(""); - _console.println(BOILER_PLATE); + _console.println(BOILER_PLATE); runCLI(); } @@ -495,13 +495,13 @@ public class MessageStoreTool if (_exchange != null) { status.append("["); - status.append(_exchange.getName()); + status.append(_exchange.getNameShortString()); status.append("]"); if (_queue != null) { status.append("->'"); - status.append(_queue.getName()); + status.append(_queue.getNameShortString()); status.append("'"); if (_msgids != null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java index ef3599bdc8..348c95572d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -52,7 +52,7 @@ public class Copy extends Move protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) { ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), txn); + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getNameShortString().toString(), txn); txn.commit(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java index ab8e781df5..3c4a0c8fac 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -292,12 +292,12 @@ public class List extends AbstractCommand { if (exchange.isBound(queue)) { - data.add(queue.getName().toString()); + data.add(queue.getNameShortString().toString()); } } else { - data.add(queue.getName().toString()); + data.add(queue.getNameShortString().toString()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java index 6a5e2a6025..615f6ec1c2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -196,7 +196,7 @@ public class Move extends AbstractCommand protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) { ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), txn); + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getNameShortString().toString(), txn); txn.commit(); } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java index 89b825b270..e478f0f1f3 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java @@ -20,20 +20,11 @@ */ package org.apache.qpid.server.configuration; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Collections; - import junit.framework.TestCase; - import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; + import org.apache.qpid.server.protocol.AMQProtocolEngine; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -42,6 +33,14 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.transport.TestNetworkDriver; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + public class ServerConfigurationTest extends TestCase { @@ -51,7 +50,7 @@ public class ServerConfigurationTest extends TestCase public void setUp() { //Highlight that this test will cause a new AR to be created - ApplicationRegistry.getInstance(); +// ApplicationRegistry.getInstance(); _config = new XMLConfiguration(); } @@ -60,7 +59,7 @@ public class ServerConfigurationTest extends TestCase public void tearDown() throws Exception { //Correctly Close the AR we created - ApplicationRegistry.remove(); +// ApplicationRegistry.remove(); } public void testSetJMXManagementPort() throws ConfigurationException @@ -765,21 +764,28 @@ public class ServerConfigurationTest extends TestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg, 1); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); - VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); + // Test config + VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); + VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); - TestNetworkDriver testDriver = new TestNetworkDriver(); - testDriver.setRemoteAddress("127.0.0.1"); + TestNetworkDriver testDriver = new TestNetworkDriver(); + testDriver.setRemoteAddress("127.0.0.1"); - AMQProtocolEngine session = new AMQProtocolEngine(virtualHostRegistry, testDriver); - assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + AMQProtocolEngine session = new AMQProtocolEngine(virtualHostRegistry, testDriver); + assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); - testDriver.setRemoteAddress("127.1.2.3"); - session = new AMQProtocolEngine(virtualHostRegistry, testDriver); - assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost)); + testDriver.setRemoteAddress("127.1.2.3"); + session = new AMQProtocolEngine(virtualHostRegistry, testDriver); + assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost)); + } + finally + { + ApplicationRegistry.remove(1); + } } public void testCombinedConfigurationFirewall() throws Exception @@ -839,48 +845,61 @@ public class ServerConfigurationTest extends TestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg, 1); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); - VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); + // Test config + VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); + VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); - TestNetworkDriver testDriver = new TestNetworkDriver(); - testDriver.setRemoteAddress("127.0.0.1"); + TestNetworkDriver testDriver = new TestNetworkDriver(); + testDriver.setRemoteAddress("127.0.0.1"); - AMQProtocolEngine session = new AMQProtocolEngine(virtualHostRegistry, testDriver); - session.setNetworkDriver(testDriver); - assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + AMQProtocolEngine session = new AMQProtocolEngine(virtualHostRegistry, testDriver); + session.setNetworkDriver(testDriver); + assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + } + finally + { + ApplicationRegistry.remove(1); + } } - + public void testConfigurationFirewallReload() throws Exception { // Write out config File mainFile = File.createTempFile(getClass().getName(), null); - mainFile.deleteOnExit(); + mainFile.deleteOnExit(); writeConfigFile(mainFile, false); // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg, 1); - - // Test config - TestNetworkDriver testDriver = new TestNetworkDriver(); - testDriver.setRemoteAddress("127.0.0.1"); - VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); - VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); - AMQProtocolSession session = new AMQProtocolEngine(virtualHostRegistry, testDriver); - - assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); - - // Switch to deny the connection - writeConfigFile(mainFile, true); - - reg.getConfiguration().reparseConfigFileSecuritySections(); - - assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost)); + try + { + ApplicationRegistry.initialise(reg, 1); + + // Test config + TestNetworkDriver testDriver = new TestNetworkDriver(); + testDriver.setRemoteAddress("127.0.0.1"); + VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); + VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); + AMQProtocolSession session = new AMQProtocolEngine(virtualHostRegistry, testDriver); + + assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + // Switch to deny the connection + writeConfigFile(mainFile, true); + + reg.getConfiguration().reparseConfigFileSecuritySections(); + + assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost)); + } + finally + { + ApplicationRegistry.remove(1); + } } private void writeConfigFile(File mainFile, boolean allow) throws IOException { @@ -974,45 +993,52 @@ public class ServerConfigurationTest extends TestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg, 1); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - TestNetworkDriver testDriver = new TestNetworkDriver(); - testDriver.setRemoteAddress("127.0.0.1"); - VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); - VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); - AMQProtocolSession session = new AMQProtocolEngine(virtualHostRegistry, testDriver); - assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + // Test config + TestNetworkDriver testDriver = new TestNetworkDriver(); + testDriver.setRemoteAddress("127.0.0.1"); + VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); + VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); + AMQProtocolSession session = new AMQProtocolEngine(virtualHostRegistry, testDriver); + assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); - RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw"); - fileBRandom.setLength(0); - fileBRandom.seek(0); - fileBRandom.close(); + RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw"); + fileBRandom.setLength(0); + fileBRandom.seek(0); + fileBRandom.close(); - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); + out = new FileWriter(fileB); + out.write("<firewall>\n"); + out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); + out.write("</firewall>\n"); + out.close(); - reg.getConfiguration().reparseConfigFileSecuritySections(); + reg.getConfiguration().reparseConfigFileSecuritySections(); - assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost)); + assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost)); - fileBRandom = new RandomAccessFile(fileB, "rw"); - fileBRandom.setLength(0); - fileBRandom.seek(0); - fileBRandom.close(); + fileBRandom = new RandomAccessFile(fileB, "rw"); + fileBRandom.setLength(0); + fileBRandom.seek(0); + fileBRandom.close(); - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); + out = new FileWriter(fileB); + out.write("<firewall>\n"); + out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); + out.write("</firewall>\n"); + out.close(); - reg.getConfiguration().reparseConfigFileSecuritySections(); + reg.getConfiguration().reparseConfigFileSecuritySections(); - assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); + } + finally + { + ApplicationRegistry.remove(1); + } } public void testnewParserOutputVsOldParserOutput() throws ConfigurationException @@ -1038,11 +1064,18 @@ public class ServerConfigurationTest extends TestCase File configFile = new File(System.getProperty("QPID_HOME")+"/etc/config.xml"); assertTrue(configFile.exists()); - ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile), REGISTRY); + try + { + ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(configFile), REGISTRY); - VirtualHostRegistry virtualHostRegistry = ApplicationRegistry.getInstance(REGISTRY).getVirtualHostRegistry(); + VirtualHostRegistry virtualHostRegistry = ApplicationRegistry.getInstance(REGISTRY).getVirtualHostRegistry(); - assertEquals("Incorrect virtualhost count", 3 , virtualHostRegistry.getVirtualHosts().size()); + assertEquals("Incorrect virtualhost count", 3 , virtualHostRegistry.getVirtualHosts().size()); + } + finally + { + ApplicationRegistry.remove(REGISTRY); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java index b65020395c..683343aa14 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java @@ -22,12 +22,12 @@ package org.apache.qpid.server.configuration; import junit.framework.TestCase; import org.apache.commons.configuration.XMLConfiguration; + import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQPriorityQueue; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; public class VirtualHostConfigurationTest extends TestCase { @@ -39,8 +39,6 @@ public class VirtualHostConfigurationTest extends TestCase protected void setUp() throws Exception { super.setUp(); - //Highlight that this test will cause a new AR to be created - ApplicationRegistry.getInstance(); // Fill config file with stuff configXml = new XMLConfiguration(); configXml.setRootElementName("virtualhosts"); @@ -49,39 +47,37 @@ public class VirtualHostConfigurationTest extends TestCase public void tearDown() throws Exception { - //Correctly close the AR we created - ApplicationRegistry.remove(); - super.tearDown(); } public void testQueuePriority() throws Exception { + configXml.addProperty("virtualhost.testQueuePriority.name", "testQueuePriority"); // Set up queue with 5 priorities - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", + configXml.addProperty("virtualhost.testQueuePriority.queues(-1).queue(-1).name(-1)", "atest"); - configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", + configXml.addProperty("virtualhost.testQueuePriority.queues.queue.atest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.atest.priorities", + configXml.addProperty("virtualhost.testQueuePriority.queues.queue.atest.priorities", "5"); // Set up queue with JMS style priorities - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", + configXml.addProperty("virtualhost.testQueuePriority.queues(-1).queue(-1).name(-1)", "ptest"); - configXml.addProperty("virtualhost.test.queues.queue.ptest(-1).exchange", + configXml.addProperty("virtualhost.testQueuePriority.queues.queue.ptest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.ptest.priority", + configXml.addProperty("virtualhost.testQueuePriority.queues.queue.ptest.priority", "true"); // Set up queue with no priorities - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", + configXml.addProperty("virtualhost.testQueuePriority.queues(-1).queue(-1).name(-1)", "ntest"); - configXml.addProperty("virtualhost.test.queues.queue.ntest(-1).exchange", + configXml.addProperty("virtualhost.testQueuePriority.queues.queue.ntest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.ntest.priority", + configXml.addProperty("virtualhost.testQueuePriority.queues.queue.ntest.priority", "false"); - VirtualHost vhost = new VirtualHostImpl(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test"))); + VirtualHost vhost = ApplicationRegistry.getInstance().createVirtualHost(new VirtualHostConfiguration("testQueuePriority", configXml.subset("virtualhost.testQueuePriority"))); // Check that atest was a priority queue with 5 priorities AMQQueue atest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest")); @@ -96,25 +92,29 @@ public class VirtualHostConfigurationTest extends TestCase // Check that ntest wasn't a priority queue AMQQueue ntest = vhost.getQueueRegistry().getQueue(new AMQShortString("ntest")); assertFalse(ntest instanceof AMQPriorityQueue); + + ApplicationRegistry.remove(); + } public void testQueueAlerts() throws Exception { + configXml.addProperty("virtualhost.testQueueAlerts.name", "testQueueAlerts"); // Set up queue with 5 priorities - configXml.addProperty("virtualhost.test.queues.exchange", "amq.topic"); - configXml.addProperty("virtualhost.test.queues.maximumQueueDepth", "1"); - configXml.addProperty("virtualhost.test.queues.maximumMessageSize", "2"); - configXml.addProperty("virtualhost.test.queues.maximumMessageAge", "3"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.exchange", "amq.topic"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.maximumQueueDepth", "1"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.maximumMessageSize", "2"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.maximumMessageAge", "3"); - configXml.addProperty("virtualhost.test.queues(-1).queue(1).name(1)", "atest"); - configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumQueueDepth", "4"); - configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageSize", "5"); - configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageAge", "6"); + configXml.addProperty("virtualhost.testQueueAlerts.queues(-1).queue(1).name(1)", "atest"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.queue.atest(-1).exchange", "amq.direct"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.queue.atest(-1).maximumQueueDepth", "4"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.queue.atest(-1).maximumMessageSize", "5"); + configXml.addProperty("virtualhost.testQueueAlerts.queues.queue.atest(-1).maximumMessageAge", "6"); - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "btest"); + configXml.addProperty("virtualhost.testQueueAlerts.queues(-1).queue(-1).name(-1)", "btest"); - VirtualHost vhost = new VirtualHostImpl(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test"))); + VirtualHost vhost = ApplicationRegistry.getInstance().createVirtualHost(new VirtualHostConfiguration("testQueueAlerts", configXml.subset("virtualhost.testQueueAlerts"))); // Check specifically configured values AMQQueue aTest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest")); @@ -128,6 +128,9 @@ public class VirtualHostConfigurationTest extends TestCase assertEquals(2, bTest.getMaximumMessageSize()); assertEquals(3, bTest.getMaximumMessageAge()); + ApplicationRegistry.remove(); + + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java index e26b5b048c..06d5d80ac1 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java @@ -21,23 +21,41 @@ package org.apache.qpid.server.exchange; import junit.framework.TestCase; +import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.binding.BindingFactory; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.MockStoredMessage; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.SimpleAMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoredMessage; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.message.AMQMessageHeader; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.log4j.Logger; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; public class AbstractHeadersExchangeTestBase extends TestCase @@ -47,11 +65,24 @@ public class AbstractHeadersExchangeTestBase extends TestCase private final HeadersExchange exchange = new HeadersExchange(); protected final Set<TestQueue> queues = new HashSet<TestQueue>(); + + /** * Not used in this test, just there to stub out the routing calls */ private MessageStore _store = new MemoryMessageStore(); + + BindingFactory bindingFactory = new BindingFactory(new DurableConfigurationStore.Source() + { + + public DurableConfigurationStore getDurableConfigurationStore() + { + return _store; + } + }, + exchange); + private int count; public void testDoNothing() @@ -93,7 +124,7 @@ public class AbstractHeadersExchangeTestBase extends TestCase m.route(exchange); if(m.getIncomingMessage().allContentReceived()) { - for(AMQQueue q : m.getIncomingMessage().getDestinationQueues()) + for(BaseQueue q : m.getIncomingMessage().getDestinationQueues()) { q.enqueue(m); } @@ -241,15 +272,17 @@ public class AbstractHeadersExchangeTestBase extends TestCase public String toString() { - return getName().toString(); + return getNameShortString().toString(); } public TestQueue(AMQShortString name) throws AMQException { - super(name, false, new AMQShortString("test"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test")); + super(name, false, new AMQShortString("test"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"),Collections.EMPTY_MAP); ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry().registerQueue(this); } + + /** * We override this method so that the default behaviour, which attempts to use a delivery manager, is * not invoked. It is unnecessary since for this test we only care to know whether the message was @@ -258,10 +291,10 @@ public class AbstractHeadersExchangeTestBase extends TestCase * @throws AMQException */ @Override - public QueueEntry enqueue(ServerMessage msg) throws AMQException + public void enqueue(ServerMessage msg, PostEnqueueAction action) throws AMQException { messages.add( new HeadersExchangeTest.Message((AMQMessage) msg)); - return new QueueEntry() + final QueueEntry queueEntry = new QueueEntry() { public AMQQueue getQueue() @@ -289,6 +322,11 @@ public class AbstractHeadersExchangeTestBase extends TestCase return false; //To change body of implemented methods use File | Settings | File Templates. } + public boolean isAvailable() + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + public boolean isAcquired() { return false; //To change body of implemented methods use File | Settings | File Templates. @@ -439,6 +477,12 @@ public class AbstractHeadersExchangeTestBase extends TestCase return 0; //To change body of implemented methods use File | Settings | File Templates. } }; + + if(action != null) + { + action.onEnqueue(queueEntry); + } + } boolean isInQueue(Message msg) diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java index 016f7eacbe..b26c71a524 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java @@ -29,7 +29,6 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; @@ -58,8 +57,8 @@ public class ExchangeMBeanTest extends TestCase ManagedObject managedObj = exchange.getManagedObject(); ManagedExchange mbean = (ManagedExchange)managedObj; - mbean.createNewBinding(_queue.getName().toString(), "binding1"); - mbean.createNewBinding(_queue.getName().toString(), "binding2"); + mbean.createNewBinding(_queue.getNameShortString().toString(), "binding1"); + mbean.createNewBinding(_queue.getNameShortString().toString(), "binding2"); TabularData data = mbean.bindings(); ArrayList<Object> list = new ArrayList<Object>(data.values()); @@ -85,8 +84,8 @@ public class ExchangeMBeanTest extends TestCase ManagedObject managedObj = exchange.getManagedObject(); ManagedExchange mbean = (ManagedExchange)managedObj; - mbean.createNewBinding(_queue.getName().toString(), "binding1"); - mbean.createNewBinding(_queue.getName().toString(), "binding2"); + mbean.createNewBinding(_queue.getNameShortString().toString(), "binding1"); + mbean.createNewBinding(_queue.getNameShortString().toString(), "binding2"); TabularData data = mbean.bindings(); ArrayList<Object> list = new ArrayList<Object>(data.values()); @@ -112,8 +111,8 @@ public class ExchangeMBeanTest extends TestCase ManagedObject managedObj = exchange.getManagedObject(); ManagedExchange mbean = (ManagedExchange)managedObj; - mbean.createNewBinding(_queue.getName().toString(), "key1=binding1,key2=binding2"); - mbean.createNewBinding(_queue.getName().toString(), "key3=binding3"); + mbean.createNewBinding(_queue.getNameShortString().toString(), "key1=binding1,key2=binding2"); + mbean.createNewBinding(_queue.getNameShortString().toString(), "key3=binding3"); TabularData data = mbean.bindings(); ArrayList<Object> list = new ArrayList<Object>(data.values()); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java index dc47951548..1e56a32383 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java @@ -83,6 +83,16 @@ public class HeadersBindingTest extends TestCase return null; } + public String getReplyToExchange() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public String getReplyToRoutingKey() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public Object getHeader(String name) { return _headers.get(name); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java index 9d7a323b6d..daa0377e0a 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java @@ -67,11 +67,8 @@ public class TopicExchangeTest extends TestCase _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null); - MessagePublishInfo info = new PublishInfo(new AMQShortString("a.b")); - - IncomingMessage message = new IncomingMessage(info); - - message.enqueue(_exchange.route(message)); + IncomingMessage message = createMessage("a.b"); + routeMessage(message); Assert.assertEquals(0, queue.getMessageCount()); } @@ -357,7 +354,7 @@ public class TopicExchangeTest extends TestCase message.enqueue(_exchange.route(message)); AMQMessage msg = new AMQMessage(message.getStoredMessage()); - for(AMQQueue q : message.getDestinationQueues()) + for(BaseQueue q : message.getDestinationQueues()) { q.enqueue(msg); } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java index 072f671fec..174576b473 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/ExchangeMessagesTest.java @@ -37,8 +37,8 @@ public class ExchangeMessagesTest extends AbstractTestMessages getVirtualHostRegistry().getVirtualHost("test"). getExchangeRegistry().getDefaultExchange(); - String type = exchange.getType().toString(); - String name = exchange.getName().toString(); + String type = exchange.getTypeShortString().toString(); + String name = exchange.getNameShortString().toString(); _logMessage = ExchangeMessages.EXH_CREATED(type, name, false); List<Object> log = performLog(); @@ -55,8 +55,8 @@ public class ExchangeMessagesTest extends AbstractTestMessages getVirtualHostRegistry().getVirtualHost("test"). getExchangeRegistry().getDefaultExchange(); - String type = exchange.getType().toString(); - String name = exchange.getName().toString(); + String type = exchange.getTypeShortString().toString(); + String name = exchange.getNameShortString().toString(); _logMessage = ExchangeMessages.EXH_CREATED(type, name, true); List<Object> log = performLog(); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java index 905d63ea09..4d75a899be 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/AbstractTestLogSubject.java @@ -50,7 +50,7 @@ import java.util.List; * validate this class then performs a log statement with logging enabled and * logging disabled. * - * The resulting log file is then validated. + * The resulting log file is then validated. * */ public abstract class AbstractTestLogSubject extends TestCase @@ -177,7 +177,7 @@ public abstract class AbstractTestLogSubject extends TestCase assertNotNull("Queue not found:" + message, queueSlice); assertEquals("Queue name not correct", - queue.getName().toString(), queueSlice); + queue.getNameShortString().toString(), queueSlice); } /** @@ -199,10 +199,10 @@ public abstract class AbstractTestLogSubject extends TestCase exchangeParts.length); assertEquals("Exchange type not correct", - exchange.getType().toString(), exchangeParts[0]); + exchange.getTypeShortString().toString(), exchangeParts[0]); assertEquals("Exchange name not correct", - exchange.getName().toString(), exchangeParts[1]); + exchange.getNameShortString().toString(), exchangeParts[1]); } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java index 6319238841..279628501c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/subjects/BindingLogSubjectTest.java @@ -50,7 +50,7 @@ public class BindingLogSubjectTest extends AbstractTestLogSubject _queue = new MockAMQQueue("BindingLogSubjectTest"); ((MockAMQQueue) _queue).setVirtualHost(_testVhost); - _subject = new BindingLogSubject(_routingKey, _exchange, _queue); + _subject = new BindingLogSubject(String.valueOf(_routingKey), _exchange, _queue); } /** diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java index 4e5ba0213a..ea89d026ff 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java @@ -302,7 +302,7 @@ public class AMQQueueMBeanTest extends TestCase }); AMQMessage m = new AMQMessage(msg.getStoredMessage()); - for(AMQQueue q : msg.getDestinationQueues()) + for(BaseQueue q : msg.getDestinationQueues()) { q.enqueue(m); } @@ -463,7 +463,7 @@ public class AMQQueueMBeanTest extends TestCase MESSAGE_SIZE))); AMQMessage m = new AMQMessage(currentMessage.getStoredMessage()); - for(AMQQueue q : currentMessage.getDestinationQueues()) + for(BaseQueue q : currentMessage.getDestinationQueues()) { q.enqueue(m); } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java index a487b160e1..10a828d07c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java @@ -22,7 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.*; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -30,12 +30,14 @@ import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.AMQException; import java.util.List; import java.util.Set; import java.util.Map; +import java.util.UUID; public class MockAMQQueue implements AMQQueue { @@ -58,17 +60,107 @@ public class MockAMQQueue implements AMQQueue } public void setDeleteOnNoConsumers(boolean b) - { + { + } + + public void addBinding(final Binding binding) + { + + } + + public void removeBinding(final Binding binding) + { + + } + + public List<Binding> getBindings() + { + return null; + } + + public int getBindingCount() + { + return 0; + } + + public ConfigStore getConfigStore() + { + return getVirtualHost().getConfigStore(); + } + + public long getMessageDequeueCount() + { + return 0; + } + + public long getTotalEnqueueSize() + { + return 0; } - public AMQShortString getName() + public long getTotalDequeueSize() + { + return 0; + } + + public int getBindingCountHigh() + { + return 0; + } + + public long getPersistentByteEnqueues() + { + return 0; + } + + public long getPersistentByteDequeues() + { + return 0; + } + + public long getPersistentMsgEnqueues() + { + return 0; + } + + public long getPersistentMsgDequeues() + { + return 0; + } + + public void purge(final long request) + { + + } + + public long getCreateTime() + { + return 0; + } + + public AMQShortString getNameShortString() { return _name; } public void setNoLocal(boolean b) { - + + } + + public UUID getId() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public QueueConfigType getConfigType() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public ConfiguredObject getParent() + { + return null; //To change body of implemented methods use File | Settings | File Templates. } public boolean isDurable() @@ -96,6 +188,11 @@ public class MockAMQQueue implements AMQQueue return _virtualhost; } + public String getName() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException { //To change body of implemented methods use File | Settings | File Templates. @@ -106,10 +203,6 @@ public class MockAMQQueue implements AMQQueue //To change body of implemented methods use File | Settings | File Templates. } - public List<ExchangeBinding> getExchangeBindings() - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } public void registerSubscription(Subscription subscription, boolean exclusive) throws AMQException { @@ -131,6 +224,11 @@ public class MockAMQQueue implements AMQQueue return 0; //To change body of implemented methods use File | Settings | File Templates. } + public boolean hasExclusiveSubscriber() + { + return false; + } + public boolean isUnused() { return false; //To change body of implemented methods use File | Settings | File Templates. @@ -176,11 +274,15 @@ public class MockAMQQueue implements AMQQueue return 0; //To change body of implemented methods use File | Settings | File Templates. } - public QueueEntry enqueue(ServerMessage message) throws AMQException + public void enqueue(ServerMessage message) throws AMQException + { + } + + public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException { - return null; //To change body of implemented methods use File | Settings | File Templates. } + public void requeue(QueueEntry entry) { //To change body of implemented methods use File | Settings | File Templates. @@ -206,6 +308,11 @@ public class MockAMQQueue implements AMQQueue //To change body of implemented methods use File | Settings | File Templates. } + public void removeQueueDeleteTask(final Task task) + { + //To change body of implemented methods use File | Settings | File Templates. + } + public List<QueueEntry> getMessagesOnTheQueue() { return null; //To change body of implemented methods use File | Settings | File Templates. diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java index 3f74cb973b..8b894c9629 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java @@ -85,6 +85,11 @@ public class MockQueueEntry implements QueueEntry return false; } + public boolean isAvailable() + { + return false; + } + public Subscription getDeliveredSubscription() { return null; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java index 408893870b..2abeb7ed30 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java @@ -21,12 +21,9 @@ package org.apache.qpid.server.queue; */ -import java.util.ArrayList; -import java.util.List; - import junit.framework.TestCase; - import org.apache.commons.configuration.PropertiesConfiguration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -35,17 +32,21 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.DirectExchange; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.subscription.MockSubscription; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class SimpleAMQQueueTest extends TestCase { @@ -124,7 +125,7 @@ public class SimpleAMQQueueTest extends TestCase } try { - _queue = new SimpleAMQQueue(_qname, false, _owner, false, null); + _queue = new SimpleAMQQueue(_qname, false, _owner, false, null,Collections.EMPTY_MAP); assertNull("Queue was created", _queue); } catch (IllegalArgumentException e) @@ -145,31 +146,23 @@ public class SimpleAMQQueueTest extends TestCase public void testBinding() { - try - { - _queue.bind(_exchange, _routingKey, null); - assertTrue("Routing key was not bound", - _exchange.getBindings().containsKey(_routingKey)); - assertEquals("Queue was not bound to key", - _exchange.getBindings().get(_routingKey).get(0), - _queue); - assertEquals("Exchange binding count", 1, - _queue.getExchangeBindings().size()); - assertEquals("Wrong exchange bound", _routingKey, - _queue.getExchangeBindings().get(0).getRoutingKey()); - assertEquals("Wrong exchange bound", _exchange, - _queue.getExchangeBindings().get(0).getExchange()); - - _queue.unBind(_exchange, _routingKey, null); - assertFalse("Routing key was still bound", - _exchange.getBindings().containsKey(_routingKey)); - assertNull("Routing key was not empty", - _exchange.getBindings().get(_routingKey)); - } - catch (AMQException e) - { - assertNull("Unexpected exception", e); - } + _virtualHost.getBindingFactory().addBinding(String.valueOf(_routingKey), _queue, _exchange, Collections.EMPTY_MAP); + + assertTrue("Routing key was not bound", + _exchange.isBound(_routingKey)); + assertTrue("Queue was not bound to key", + _exchange.isBound(_routingKey,_queue)); + assertEquals("Exchange binding count", 1, + _queue.getBindings().size()); + assertEquals("Wrong exchange bound", String.valueOf(_routingKey), + _queue.getBindings().get(0).getBindingKey()); + assertEquals("Wrong exchange bound", _exchange, + _queue.getBindings().get(0).getExchange()); + + _virtualHost.getBindingFactory().removeBinding(String.valueOf(_routingKey), _queue, _exchange, Collections.EMPTY_MAP); + assertFalse("Routing key was still bound", + _exchange.isBound(_routingKey)); + } public void testSubscription() throws AMQException @@ -258,7 +251,7 @@ public class SimpleAMQQueueTest extends TestCase public void testAutoDeleteQueue() throws Exception { _queue.stop(); - _queue = new SimpleAMQQueue(_qname, false, null, true, _virtualHost); + _queue = new SimpleAMQQueue(_qname, false, null, true, _virtualHost, Collections.EMPTY_MAP); _queue.setDeleteOnNoConsumers(true); _queue.registerSubscription(_subscription, false); AMQMessage message = createMessage(new Long(25)); @@ -409,7 +402,7 @@ public class SimpleAMQQueueTest extends TestCase ((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) 2); msg.setContentHeaderBody(contentHeaderBody); - final ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); + final ArrayList<BaseQueue> qs = new ArrayList<BaseQueue>(); // Send persistent message diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java index 4c8ff01be0..cadde1288b 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java @@ -50,7 +50,7 @@ public class ApplicationRegistryShutdownTest extends TestCase @Override public void tearDown() throws Exception { - // Correctly Close the AR we created + // Correctly Close the AR we created ApplicationRegistry.remove(); } @@ -58,22 +58,15 @@ public class ApplicationRegistryShutdownTest extends TestCase /** * QPID-1399 : Ensure that the Authentiction manager unregisters any SASL providers created during * ApplicationRegistry initialisation. - * + * */ - public void testAuthenticationMangerCleansUp() + public void testAuthenticationMangerCleansUp() throws Exception { // Get default providers Provider[] defaultProviders = Security.getProviders(); // Register new providers - try - { - _registry.initialise(ApplicationRegistry.DEFAULT_INSTANCE); - } - catch (Exception e) - { - fail(e.getMessage()); - } + ApplicationRegistry.initialise(_registry, ApplicationRegistry.DEFAULT_INSTANCE); // Get the providers after initialisation Provider[] providersAfterInitialisation = Security.getProviders(); @@ -103,16 +96,9 @@ public class ApplicationRegistryShutdownTest extends TestCase assertTrue("No new SASL mechanisms added by initialisation.", additions.size() != 0 ); //Close the registry which will perform the close the AuthenticationManager - try - { - _registry.close(); - } - catch (Exception e) - { - fail(e.getMessage()); - } + _registry.close(); - //Validate that the SASL plugins have been removed. + //Validate that the SASL plugFins have been removed. Provider[] providersAfterClose = Security.getProviders(); assertTrue("No providers unregistered", providersAfterInitialisation.length > providersAfterClose.length); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java index 73e9dac775..df466380b9 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -23,19 +23,16 @@ package org.apache.qpid.server.security.access; import junit.framework.TestCase; -import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.amqp_0_9.ExchangeDeclareBodyImpl; import org.apache.qpid.framing.amqp_8_0.QueueBindBodyImpl; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.DirectExchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.registry.ApplicationRegistry; public class PrincipalPermissionsTest extends TestCase { @@ -74,8 +71,7 @@ public class PrincipalPermissionsTest extends TestCase _perms = new PrincipalPermissions(_user); try { - PropertiesConfiguration env = new PropertiesConfiguration(); - _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration("test", env)); + _virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete); _queue = AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, _virtualHost, _arguments); _temporaryQueue = AMQQueueFactory.createAMQQueueImpl(_tempQueueName, false, _owner , true, _virtualHost, _arguments); @@ -106,7 +102,7 @@ public class PrincipalPermissionsTest extends TestCase { QueueBindBodyImpl bind = new QueueBindBodyImpl(_ticket, _queueName, _exchangeName, _routingKey, _nowait, _arguments); Object[] args = new Object[]{bind, _exchange, _queue, _routingKey}; - + assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.BIND, args)); _perms.grant(Permission.BIND, (Object[]) null); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.BIND, args)); @@ -116,7 +112,7 @@ public class PrincipalPermissionsTest extends TestCase { Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, _routingKey}; Object[] authArgs = new Object[]{_autoDelete, _queueName}; - + assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); _perms.grant(Permission.CREATEQUEUE, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); @@ -157,12 +153,12 @@ public class PrincipalPermissionsTest extends TestCase _perms.grant(Permission.CONSUME, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authArgs)); } - + public void testPublish() { Object[] authArgs = new Object[]{_exchange, _routingKey}; - Object[] grantArgs = new Object[]{_exchange.getName(), _routingKey}; - + Object[] grantArgs = new Object[]{_exchange.getNameShortString(), _routingKey}; + assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.PUBLISH, authArgs)); _perms.grant(Permission.PUBLISH, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgs)); @@ -171,28 +167,28 @@ public class PrincipalPermissionsTest extends TestCase public void testVhostAccess() { //Tests that granting a user Virtualhost level access allows all authorisation requests - //where previously they would be denied - + //where previously they would be denied + //QPID-2133 createExchange rights currently allow all exchange creation unless rights for creating some //specific exchanges are granted. Grant a specific exchange creation to cause all others to be denied. Object[] createArgsCreateExchange = new Object[]{new AMQShortString("madeup"), _exchangeType}; Object[] authArgsCreateExchange = new Object[]{_exchangeName,_exchangeType}; assertEquals("Exchange creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange)); _perms.grant(Permission.CREATEEXCHANGE, createArgsCreateExchange); - - Object[] authArgsPublish = new Object[]{_exchange, _routingKey}; + + Object[] authArgsPublish = new Object[]{_exchange, _routingKey}; Object[] authArgsConsume = new Object[]{_queue}; Object[] authArgsCreateQueue = new Object[]{_autoDelete, _queueName}; QueueBindBodyImpl bind = new QueueBindBodyImpl(_ticket, _queueName, _exchangeName, _routingKey, _nowait, _arguments); Object[] authArgsBind = new Object[]{bind, _exchange, _queue, _routingKey}; - + assertEquals("Exchange creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange)); assertEquals("Publish was not denied", AuthzResult.DENIED, _perms.authorise(Permission.PUBLISH, authArgsPublish)); assertEquals("Consume creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.CONSUME, authArgsConsume)); assertEquals("Queue creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgsCreateQueue)); //BIND pre-grant authorise check disabled due to QPID-1597 //assertEquals("Binding creation was not denied", AuthzResult.DENIED, _perms.authorise(Permission.BIND, authArgsBind)); - + _perms.grant(Permission.ACCESS); assertEquals("Exchange creation was not allowed", AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange)); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java index 5b76bf7532..3f9c776aa2 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java @@ -49,7 +49,7 @@ public class QueueDenier extends AllowAll @Override public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { - if (!(queue.getName().toString().equals(_queueName))) + if (!(queue.getNameShortString().toString().equals(_queueName))) { return AuthzResult.ALLOWED; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java index e011301f06..2427e28e70 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java @@ -21,33 +21,39 @@ package org.apache.qpid.server.store; import junit.framework.TestCase; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.amqp_8_0.BasicConsumeBodyImpl; +import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.DirectExchange; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.exchange.TopicExchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.server.txn.AutoCommitTransaction; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.amqp_8_0.BasicConsumeBodyImpl; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.AMQException; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.qpid.server.queue.AMQPriorityQueue; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.BaseQueue; +import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.SimpleAMQQueue; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.io.File; import java.util.List; @@ -99,8 +105,7 @@ public class MessageStoreTest extends TestCase try { - _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration(getClass().getName(), configuration)); - ApplicationRegistry.getInstance().getVirtualHostRegistry().registerVirtualHost(_virtualHost); + _virtualHost = ApplicationRegistry.getInstance().createVirtualHost(new VirtualHostConfiguration(getClass().getName(), configuration)); } catch (Exception e) { @@ -244,10 +249,10 @@ public class MessageStoreTest extends TestCase { QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); - validateBindingProperties(queueRegistry.getQueue(durablePriorityQueueName).getExchangeBindings(), false); - validateBindingProperties(queueRegistry.getQueue(durablePriorityTopicQueueName).getExchangeBindings(), true); - validateBindingProperties(queueRegistry.getQueue(durableQueueName).getExchangeBindings(), false); - validateBindingProperties(queueRegistry.getQueue(durableTopicQueueName).getExchangeBindings(), true); + validateBindingProperties(queueRegistry.getQueue(durablePriorityQueueName).getBindings(), false); + validateBindingProperties(queueRegistry.getQueue(durablePriorityTopicQueueName).getBindings(), true); + validateBindingProperties(queueRegistry.getQueue(durableQueueName).getBindings(), false); + validateBindingProperties(queueRegistry.getQueue(durableTopicQueueName).getBindings(), true); } /** @@ -256,16 +261,16 @@ public class MessageStoreTest extends TestCase * @param bindings the set of bindings to validate * @param useSelectors if set validate that the binding has a JMS_SELECTOR argument */ - private void validateBindingProperties(List<ExchangeBinding> bindings, boolean useSelectors) + private void validateBindingProperties(List<Binding> bindings, boolean useSelectors) { assertEquals("Each queue should only be bound once.", 1, bindings.size()); - ExchangeBinding binding = bindings.get(0); + Binding binding = bindings.get(0); if (useSelectors) { assertTrue("Binding does not contain a Selector argument.", - binding.getArguments().containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue())); + binding.getArguments().containsKey(AMQPFilterTypes.JMS_SELECTOR.toString())); } } @@ -376,7 +381,7 @@ public class MessageStoreTest extends TestCase { // TODO Deliver to queues ServerTransaction trans = new AutoCommitTransaction(_virtualHost.getMessageStore()); - final List<AMQQueue> destinationQueues = currentMessage.getDestinationQueues(); + final List<? extends BaseQueue> destinationQueues = currentMessage.getDestinationQueues(); trans.enqueue(currentMessage.getDestinationQueues(), currentMessage, new ServerTransaction.Action() { public void postCommit() { @@ -384,9 +389,9 @@ public class MessageStoreTest extends TestCase { AMQMessage message = new AMQMessage(currentMessage.getStoredMessage()); - for(AMQQueue queue : destinationQueues) + for(BaseQueue queue : destinationQueues) { - QueueEntry entry = queue.enqueue(message); + queue.enqueue(message); } } catch (AMQException e) @@ -525,14 +530,7 @@ public class MessageStoreTest extends TestCase protected void bindQueueToExchange(Exchange exchange, AMQShortString routingKey, AMQQueue queue, boolean useSelector, FieldTable queueArguments) { - try - { - exchange.registerQueue(queueName, queue, queueArguments); - } - catch (AMQException e) - { - fail(e.getMessage()); - } + FieldTable bindArguments = null; @@ -544,9 +542,9 @@ public class MessageStoreTest extends TestCase try { - queue.bind(exchange, routingKey, bindArguments); + _virtualHost.getBindingFactory().addBinding(String.valueOf(routingKey), queue, exchange, FieldTable.convertToMap(bindArguments)); } - catch (AMQException e) + catch (Exception e) { fail(e.getMessage()); } @@ -609,7 +607,7 @@ public class MessageStoreTest extends TestCase public AMQShortString getExchange() { - return _exchange.getName(); + return _exchange.getNameShortString(); } public void setExchange(AMQShortString exchange) diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java index 906c769f9c..85412cf74e 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java @@ -74,7 +74,7 @@ public class InternalBrokerBaseCase extends TestCase Exchange defaultExchange = _virtualHost.getExchangeRegistry().getDefaultExchange(); - _queue.bind(defaultExchange, QUEUE_NAME, null); + _virtualHost.getBindingFactory().addBinding(QUEUE_NAME.toString(), _queue, defaultExchange, null); _session = new InternalTestProtocolSession(_virtualHost); CurrentActor.set(_session.getLogActor()); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 3d37412376..d927bbe732 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -22,12 +22,14 @@ package org.apache.qpid.server.util; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; + +import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.TestLogActor; -import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.plugins.PluginManager; @@ -36,14 +38,13 @@ import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import java.util.Arrays; import java.util.Collection; -import java.util.Properties; import java.util.NoSuchElementException; +import java.util.Properties; public class NullApplicationRegistry extends ApplicationRegistry { @@ -75,10 +76,11 @@ public class NullApplicationRegistry extends ApplicationRegistry _managedObjectRegistry = new NoopManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(this); + _qmfService = new QMFService(getConfigStore(),this); + PropertiesConfiguration vhostProps = new PropertiesConfiguration(); VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); - VirtualHost dummyHost = new VirtualHostImpl(hostConfig); - _virtualHostRegistry.registerVirtualHost(dummyHost); + VirtualHost dummyHost = ApplicationRegistry.getInstance().createVirtualHost(hostConfig); _virtualHostRegistry.setDefaultVirtualHostName("test"); _pluginManager = new PluginManager(""); _startup = new Exception("NAR"); @@ -99,6 +101,7 @@ public class NullApplicationRegistry extends ApplicationRegistry try { super.close(); + _qmfService.close(); } finally { diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java index bb338458f1..b5bbfde514 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java @@ -22,10 +22,16 @@ package org.apache.qpid.server.util; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; + +import org.apache.qpid.qmf.QMFService; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.logging.RootMessageLoggerImpl; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.TestLogActor; +import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -35,17 +41,13 @@ import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabase import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStore; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.logging.RootMessageLoggerImpl; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.TestLogActor; -import org.apache.qpid.server.logging.rawloggers.Log4jMessageLogger; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import java.util.Arrays; import java.util.Collection; import java.util.Properties; -import java.util.Arrays; public class TestApplicationRegistry extends ApplicationRegistry { @@ -97,6 +99,8 @@ public class TestApplicationRegistry extends ApplicationRegistry _messageStore = new TestableMemoryMessageStore(); _virtualHostRegistry = new VirtualHostRegistry(this); + _qmfService = new QMFService(getConfigStore(),this); + PropertiesConfiguration vhostProps = new PropertiesConfiguration(); VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); @@ -147,6 +151,7 @@ public class TestApplicationRegistry extends ApplicationRegistry try { super.close(); + _qmfService.close(); } finally { diff --git a/qpid/java/broker/src/xsl/qmf.xsl b/qpid/java/broker/src/xsl/qmf.xsl new file mode 100644 index 0000000000..3133674de1 --- /dev/null +++ b/qpid/java/broker/src/xsl/qmf.xsl @@ -0,0 +1,842 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output omit-xml-declaration="yes" /> +<xsl:template match="/"> +/* + * + * 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.qpid.qmf.schema; + +import org.apache.qpid.qmf.*; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.transport.codec.BBEncoder; +import org.apache.qpid.transport.codec.BBDecoder; + +import java.util.Arrays; +import java.util.UUID; +import java.util.Map; + + <xsl:apply-templates select="descendant-or-self::node()[name()='schema']" mode="schema"/> + +</xsl:template> + +<xsl:template match="node()[name()='schema']" mode="schema"> + +<xsl:variable name="schemaName"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input" select="@package"/><xsl:with-param name="arg">.</xsl:with-param></xsl:call-template></xsl:variable> +<xsl:variable name="ClassName"><xsl:call-template name="initCap"><xsl:with-param name="input" select="$schemaName"></xsl:with-param></xsl:call-template>Schema</xsl:variable> +<xsl:variable name="classList"><xsl:apply-templates select="node()[name()='class']" mode="classList"/></xsl:variable> +<xsl:variable name="eventList"><xsl:apply-templates select="node()[name()='event']" mode="eventList"/></xsl:variable> + +public class <xsl:value-of select="$ClassName"/> extends QMFPackage +{ + private static final byte QMF_VERSION = (byte) '2'; + + private static final BrokerSchema PACKAGE = new <xsl:value-of select="$ClassName"/>(); + private static final String SCHEMA_NAME = "<xsl:value-of select="@package"/>"; + +<xsl:text disable-output-escaping="yes"> + + protected abstract class QMFInfoCommand<T extends QMFObject> extends QMFCommand + { + private final T _object; + private final long _sampleTime; + + + protected QMFInfoCommand(QMFCommand trigger, QMFOperation op, T object, long sampleTime) + { + this(trigger.getHeader().getVersion(), + trigger.getHeader().getSeq(), + op, + object, + sampleTime); + } + + protected QMFInfoCommand(QMFOperation op, T object, long sampleTime) + { + this(QMF_VERSION,0,op,object,sampleTime); + } + + private QMFInfoCommand(final byte qmfVersion, + final int seq, + final QMFOperation op, + final T object, + final long sampleTime) + { + super(new QMFCommandHeader(qmfVersion, seq,op)); + _object = object; + _sampleTime = sampleTime; + } + + public T getObject() + { + return _object; + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + encoder.writeStr8(SCHEMA_NAME); + encoder.writeStr8(_object.getQMFClass().getName()); + encoder.writeBin128(new byte[16]); + encoder.writeUint64(_sampleTime * 1000000L); + encoder.writeUint64(_object.getCreateTime() * 1000000L); + encoder.writeUint64(_object.getDeleteTime() * 1000000L); + encoder.writeBin128(_object.getId()); + } + } + + protected abstract class QMFConfigInfoCommand<T extends QMFObject> extends QMFInfoCommand<T> + { + protected QMFConfigInfoCommand(T object, long sampleTime) + { + super(QMFOperation.CONFIG_INDICATION, object, sampleTime); + } + } + + protected abstract class QMFInstrumentInfoCommand<T extends QMFObject> extends QMFInfoCommand<T> + { + protected QMFInstrumentInfoCommand(T object, long sampleTime) + { + super(QMFOperation.INSTRUMENTATION_INDICATION, object, sampleTime); + } + } + + protected abstract class QMFGetQueryResponseCommand<T extends QMFObject> extends QMFInfoCommand<T> + { + protected QMFGetQueryResponseCommand(T object, QMFGetQueryCommand cmd, long sampleTime) + { + super(cmd, QMFOperation.GET_QUERY_RESPONSE, object, sampleTime); + } + } + + +</xsl:text> + + <xsl:apply-templates select="node()[name()='class']" mode="class"/> + + <xsl:apply-templates select="node()[name()='event']" mode="event"/> + + private <xsl:value-of select="$ClassName"/>() + { + super(SCHEMA_NAME); + setClasses( Arrays.asList( new QMFClass[] { <xsl:value-of select="$classList"/>, <xsl:value-of select="$eventList"/> } ) ); + } +<xsl:text disable-output-escaping="yes"> + public <T extends QMFClass> T getQMFClassInstance(Class<T> clazz) + { + for(QMFClass c : getClasses()) + { + if(clazz.isInstance(c)) + { + return (T) c; + } + } + return null; + } +</xsl:text> + + + public static BrokerSchema getPackage() + { + return PACKAGE; + } + +} +</xsl:template> + + +<xsl:template match="node()[name()='class']" mode="class"> + <xsl:variable name="ClassName"><xsl:value-of select="@name"/>Class</xsl:variable> + <xsl:variable name="name"><xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template></xsl:variable> + <xsl:variable name="propertyList"><xsl:apply-templates select="node()[name()='property']" mode="propertyList"/></xsl:variable> + <xsl:variable name="statisticList"><xsl:apply-templates select="node()[name()='statistic']" mode="statisticList"/></xsl:variable> + <xsl:variable name="methodList"><xsl:apply-templates select="node()[name()='method']" mode="methodList"/></xsl:variable> + + public class <xsl:value-of select="$ClassName"/> extends QMFObjectClass<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="@name"/>Object, <xsl:value-of select="@name"/>Delegate<xsl:text disable-output-escaping="yes">></xsl:text> + { + <xsl:apply-templates select="node()[name()='property']" mode="property"/> + + <xsl:apply-templates select="node()[name()='statistic']" mode="statistic"/> + + <xsl:apply-templates select="node()[name()='method']" mode="method"><xsl:with-param name="qmfClass" select="@name"/></xsl:apply-templates> + + private <xsl:value-of select="$ClassName"/>() + { + super("<xsl:value-of select="$name"/>", + new byte[16]); + + setProperties( Arrays.asList( new QMFProperty[] { <xsl:value-of select="$propertyList"/> } ) ); + setStatistics( Arrays.asList( new QMFStatistic[] { <xsl:value-of select="$statisticList"/> } ) ); + setMethods( Arrays.asList( new QMFMethod[] { <xsl:value-of select="$methodList"/> } ) ); + } + + public <xsl:value-of select="@name"/>Object newInstance(final <xsl:value-of select="@name"/>Delegate delegate) + { + return new <xsl:value-of select="@name"/>Object(delegate); + } + + } + + private final <xsl:value-of select="$ClassName"/> _<xsl:value-of select="$name"/>Class = new <xsl:value-of select="$ClassName"/>(); + + public interface <xsl:value-of select="@name"/>Delegate extends QMFObject.Delegate + {<xsl:apply-templates select="node()[name()='property']" mode="propertyGetter"/> + <xsl:apply-templates select="node()[name()='statistic']" mode="propertyGetter"/> + <xsl:apply-templates select="node()[name()='method']" mode="methodDefinition"><xsl:with-param name="qmfClass" select="@name"/><xsl:with-param name="delegate">Y</xsl:with-param></xsl:apply-templates> + } + + public final class <xsl:value-of select="@name"/>Object extends QMFObject<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="$ClassName"/>, <xsl:value-of select="@name"/>Delegate<xsl:text disable-output-escaping="yes">></xsl:text> + { + protected <xsl:value-of select="@name"/>Object(<xsl:value-of select="@name"/>Delegate delegate) + { + super(delegate); + } + + public <xsl:value-of select="@name"/>Class getQMFClass() + { + return _<xsl:value-of select="$name"/>Class; + } + + public QMFCommand asConfigInfoCmd(long sampleTime) + { + return new QMF<xsl:value-of select="@name"/>ConfigInfoCommand(this,sampleTime); + } + + public QMFCommand asInstrumentInfoCmd(long sampleTime) + { + return new QMF<xsl:value-of select="@name"/>InstrumentInfoCommand(this,sampleTime); + } + + public QMFCommand asGetQueryResponseCmd(QMFGetQueryCommand queryCommand, long sampleTime) + { + return new QMF<xsl:value-of select="@name"/>GetQueryResponseCommand(this,queryCommand,sampleTime); + } + + + <xsl:apply-templates select="node()[name()='method']" mode="methodDefinition"><xsl:with-param name="qmfClass" select="@name"/></xsl:apply-templates> + + <xsl:apply-templates select="node()[name()='property']" mode="propertyDelegation"/> + <xsl:apply-templates select="node()[name()='statistic']" mode="propertyDelegation"/> + } + + public final class QMF<xsl:value-of select="@name"/>ConfigInfoCommand extends QMFConfigInfoCommand<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="@name"/>Object<xsl:text disable-output-escaping="yes">></xsl:text> + { + + protected QMF<xsl:value-of select="@name"/>ConfigInfoCommand(<xsl:value-of select="@name"/>Object object, long sampleTime) + { + super(object, sampleTime); + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + <xsl:apply-templates select="node()[name()='property']" mode="optionalPropertyPresence"/> + <xsl:apply-templates select="node()[name()='property']" mode="encodeProperty"/> + } + } + + public final class QMF<xsl:value-of select="@name"/>InstrumentInfoCommand extends QMFInstrumentInfoCommand<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="@name"/>Object<xsl:text disable-output-escaping="yes">></xsl:text> + { + + protected QMF<xsl:value-of select="@name"/>InstrumentInfoCommand(<xsl:value-of select="@name"/>Object object, long sampleTime) + { + super(object, sampleTime); + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + <xsl:apply-templates select="node()[name()='statistic']" mode="optionalPropertyPresence"><xsl:with-param name="type">statistic</xsl:with-param></xsl:apply-templates> + <xsl:apply-templates select="node()[name()='statistic']" mode="encodeProperty"/> + } + } + + public final class QMF<xsl:value-of select="@name"/>GetQueryResponseCommand extends QMFGetQueryResponseCommand<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="@name"/>Object<xsl:text disable-output-escaping="yes">></xsl:text> + { + + protected QMF<xsl:value-of select="@name"/>GetQueryResponseCommand(<xsl:value-of select="@name"/>Object object, QMFGetQueryCommand cmd, long sampleTime) + { + super(object, cmd, sampleTime); + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + <xsl:apply-templates select="node()[name()='property' or name()='statistic']" mode="optionalPropertyPresence"/> + <xsl:apply-templates select="node()[name()='property' or name()='statistic']" mode="encodeProperty"/> + } + } + + + + +</xsl:template> + + <xsl:template match="node()[attribute::optional]" mode="optionalPropertyPresence"> + <xsl:param name="type">property</xsl:param> + <xsl:variable name="var">presence<xsl:value-of select="floor(count(preceding-sibling::node()[name()=$type and attribute::optional]) div 8)"/></xsl:variable> + <xsl:if test="count(preceding-sibling::node()[name()=$type and attribute::optional]) mod 8 = 0"> + byte <xsl:value-of select="$var"/> = (byte) 0; + </xsl:if> + if( getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>() != null ) + { + <xsl:value-of select="$var"/> |= (1 <xsl:text disable-output-escaping="yes"><<</xsl:text> <xsl:value-of select="count(preceding-sibling::node()[name()=$type and attribute::optional])"/>); + } + <xsl:if test="count(preceding-sibling::node()[name()=$type and attribute::optional]) mod 8 = 7 or count(following-sibling::node()[name()=$type and attribute::optional]) = 0"> + encoder.writeUint8( <xsl:value-of select="$var"/> ); + </xsl:if> + </xsl:template> + + <xsl:template match="node()" mode="propertyGetter"><xsl:text> + </xsl:text><xsl:choose> + + <xsl:when test="@type='hilo32'"> + <xsl:call-template name="javaType"><xsl:with-param name="type">count32</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>();<xsl:text> + </xsl:text><xsl:call-template name="javaType"><xsl:with-param name="type">count32</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>High();<xsl:text> + </xsl:text><xsl:call-template name="javaType"><xsl:with-param name="type">count32</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Low();</xsl:when> + + <xsl:when test="@type='mmaTime'"> + <xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Samples();<xsl:text> + </xsl:text><xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Min();<xsl:text> + </xsl:text><xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Max();<xsl:text> + </xsl:text><xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Average();</xsl:when> + + <xsl:otherwise><xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"/><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>();</xsl:otherwise> + </xsl:choose></xsl:template> + + + <xsl:template match="node()" mode="propertyDelegation"><xsl:text> + </xsl:text><xsl:choose> + <xsl:when test="@type='hilo32'"> + public <xsl:call-template name="javaType"><xsl:with-param name="type">count32</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>(); + } + + public <xsl:call-template name="javaType"><xsl:with-param name="type">count32</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>High</xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>High</xsl:with-param></xsl:call-template>(); + } + + public <xsl:call-template name="javaType"><xsl:with-param name="type">count32</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Low</xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Low</xsl:with-param></xsl:call-template>(); + } + + </xsl:when> + <xsl:when test="@type='mmaTime'"> + public <xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Samples</xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Samples</xsl:with-param></xsl:call-template>(); + } + + public <xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Min</xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Min</xsl:with-param></xsl:call-template>(); + } + + public <xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Max</xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Max</xsl:with-param></xsl:call-template>(); + } + + public <xsl:call-template name="javaType"><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Average</xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/>Average</xsl:with-param></xsl:call-template>(); + } + + </xsl:when> + <xsl:otherwise> + public <xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"/><xsl:with-param name="referenceType" select="@references"/></xsl:call-template> get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>() + { + return getDelegate().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>(); + } + + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="node()" mode="encodeProperty"> + <xsl:variable name="prop">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>()</xsl:variable> + <xsl:choose> + <xsl:when test="@optional"> + if(<xsl:value-of select="$prop"/> != null) + { + encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var" select="$prop"/><xsl:with-param name="type" select="@type"/></xsl:call-template>; + } + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="@type='hilo32'"><xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var" select="$prop"/><xsl:with-param name="type">count32</xsl:with-param></xsl:call-template>;<xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>High()</xsl:with-param><xsl:with-param name="type">count32</xsl:with-param></xsl:call-template>;<xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Low()</xsl:with-param><xsl:with-param name="type">count32</xsl:with-param></xsl:call-template>; + </xsl:when> + + <xsl:when test="@type='mmaTime'"><xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Samples()</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param></xsl:call-template>;<xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Min()</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param></xsl:call-template>;<xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Max()</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param></xsl:call-template>;<xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var">getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Average()</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param></xsl:call-template>; + </xsl:when> + + <xsl:otherwise><xsl:text> + </xsl:text>encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="var" select="$prop"/><xsl:with-param name="type" select="@type"/></xsl:call-template>; + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + + + </xsl:template> + + <xsl:template match="node()[name()='property']" mode="property"> + <xsl:variable name="ClassName"><xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Property</xsl:variable> + public class <xsl:value-of select="$ClassName"/> extends QMFProperty + { + + private <xsl:value-of select="$ClassName"/>() + { + super( "<xsl:value-of select="@name"/>", + QMFType.<xsl:call-template name="qmfType"><xsl:with-param name="type" select="@type"></xsl:with-param></xsl:call-template>, + QMFProperty.AccessCode.<xsl:call-template name="toUpper"><xsl:with-param name="input" select="@access"></xsl:with-param></xsl:call-template>, + <xsl:choose><xsl:when test="@index='y'">true</xsl:when><xsl:otherwise>false</xsl:otherwise></xsl:choose>, + <xsl:choose><xsl:when test="@optional='y'">true</xsl:when><xsl:otherwise>false</xsl:otherwise></xsl:choose>); +<xsl:if test="@desc"> + setDescription("<xsl:value-of select="@desc"/>"); +</xsl:if> +<xsl:if test="@min"> + setMin(<xsl:value-of select="@min"/>); +</xsl:if> +<xsl:if test="@max"> + setMin(<xsl:value-of select="@max"/>); +</xsl:if> +<xsl:if test="@references"> + setReferencedClass("<xsl:call-template name="initLower"><xsl:with-param name="input"><xsl:value-of select="@references"/></xsl:with-param></xsl:call-template>"); +</xsl:if> + + <xsl:if test="@unit"> + setUnit("<xsl:value-of select="@unit"/>"); + </xsl:if> + } + } + + private final <xsl:value-of select="$ClassName"/> _<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>Property = new <xsl:value-of select="$ClassName"/>(); + </xsl:template> + + <xsl:template match="node()[name()='statistic']" mode="statistic"> + <xsl:choose> + <xsl:when test="@type='hilo32'"> + <xsl:call-template name="statdef"><xsl:with-param name="name" select="@name"/><xsl:with-param name="type">uint32</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc" select="@desc"/></xsl:call-template> + <xsl:call-template name="statdef"><xsl:with-param name="name"><xsl:value-of select="@name"/>High</xsl:with-param><xsl:with-param name="type">uint32</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc"><xsl:value-of select="@desc"/> (High)</xsl:with-param></xsl:call-template> + <xsl:call-template name="statdef"><xsl:with-param name="name"><xsl:value-of select="@name"/>Low</xsl:with-param><xsl:with-param name="type">uint32</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc"><xsl:value-of select="@desc"/> (Low)</xsl:with-param></xsl:call-template> + </xsl:when> + <xsl:when test="@type='mmaTime'"> + <xsl:call-template name="statdef"><xsl:with-param name="name"><xsl:value-of select="@name"/>Samples</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc"><xsl:value-of select="@desc"/> (Samples)</xsl:with-param></xsl:call-template> + <xsl:call-template name="statdef"><xsl:with-param name="name"><xsl:value-of select="@name"/>Max</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc"><xsl:value-of select="@desc"/> (Max)</xsl:with-param></xsl:call-template> + <xsl:call-template name="statdef"><xsl:with-param name="name"><xsl:value-of select="@name"/>Min</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc"><xsl:value-of select="@desc"/> (Min)</xsl:with-param></xsl:call-template> + <xsl:call-template name="statdef"><xsl:with-param name="name"><xsl:value-of select="@name"/>Average</xsl:with-param><xsl:with-param name="type">deltaTime</xsl:with-param><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc"><xsl:value-of select="@desc"/> (Average)</xsl:with-param></xsl:call-template> + </xsl:when> + + <xsl:otherwise><xsl:call-template name="statdef"><xsl:with-param name="name" select="@name"/><xsl:with-param name="type" select="@type"/><xsl:with-param name="unit" select="@unit"/><xsl:with-param name="desc" select="@desc"/></xsl:call-template></xsl:otherwise> + </xsl:choose> + + </xsl:template> + + <xsl:template name="statdef"> + <xsl:param name="name"/> + <xsl:param name="type"/> + <xsl:param name="unit"/> + <xsl:param name="desc"/> + <xsl:variable name="ClassName"><xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="$name"/></xsl:with-param></xsl:call-template>Statistic</xsl:variable> + public class <xsl:value-of select="$ClassName"/> extends QMFStatistic + { + + private <xsl:value-of select="$ClassName"/>() + { + super( "<xsl:value-of select="$name"/>", QMFType.<xsl:call-template name="qmfType"><xsl:with-param name="type" select="$type"></xsl:with-param></xsl:call-template>, <xsl:choose> + <xsl:when test="$unit">"<xsl:value-of select="$unit"/>"</xsl:when> + <xsl:otherwise>null</xsl:otherwise> + </xsl:choose>, <xsl:choose> + <xsl:when test="$desc">"<xsl:value-of select="$desc"/>"</xsl:when> + <xsl:otherwise>null</xsl:otherwise> + </xsl:choose>); + } + } + + private final <xsl:value-of select="$ClassName"/> _<xsl:call-template name="initLower"><xsl:with-param name="input" select="$name"/></xsl:call-template>Statistic = new <xsl:value-of select="$ClassName"/>(); + </xsl:template> + + + <xsl:template match="node()[name()='method']" mode="method"> + <xsl:param name="qmfClass"/> + <xsl:variable name="ClassName"><xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Method</xsl:variable> + public class <xsl:value-of select="$ClassName"/> extends QMFMethod<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="$qmfClass"/>Object<xsl:text disable-output-escaping="yes">></xsl:text> + { + private <xsl:value-of select="$ClassName"/>() + { + super( "<xsl:value-of select="@name"/>", <xsl:choose> + <xsl:when test="@desc">"<xsl:value-of select="@desc"/>"</xsl:when> + <xsl:otherwise>null</xsl:otherwise> +</xsl:choose>); + + <xsl:apply-templates select="node()[name()='arg']" mode="argument"/> + + } + + + public <xsl:value-of select="$ClassName"/>Invocation parse(BBDecoder decoder) + { + <xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="decodeArg"/> + return new <xsl:value-of select="$ClassName"/>Invocation(<xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"/>); + } + } + + private final <xsl:value-of select="$ClassName"/> _<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>Method = new <xsl:value-of select="$ClassName"/>(); + + private class <xsl:value-of select="$ClassName"/>Invocation implements QMFMethodInvocation<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="$qmfClass"/>Object<xsl:text disable-output-escaping="yes">></xsl:text> + { + <xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodInputArgDecl"/> + + private <xsl:value-of select="$ClassName"/>Invocation(<xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="includeType">yes</xsl:with-param></xsl:apply-templates>) + { + <xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodInputArgAssign"/> + } + + public QMFMethodResponseCommand execute(<xsl:value-of select="$qmfClass"/>Object obj, QMFMethodRequestCommand cmd) + { + return obj.<xsl:value-of select="@name"/>( new <xsl:value-of select="$ClassName"/>ResponseCommandFactory(cmd)<xsl:if test="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">, </xsl:if><xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="prefix">_</xsl:with-param></xsl:apply-templates> ); + } + } + + public final class <xsl:value-of select="$ClassName"/>ResponseCommandFactory + { + private final QMFMethodRequestCommand _requestCmd; + private <xsl:value-of select="$ClassName"/>ResponseCommandFactory(QMFMethodRequestCommand cmd) + { + _requestCmd = cmd; + } + + public <xsl:value-of select="$ClassName"/>ResponseCommand createResponseCommand( <xsl:apply-templates select="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="includeType">yes</xsl:with-param><xsl:with-param name="direction">O</xsl:with-param></xsl:apply-templates> ) + { + return new <xsl:value-of select="$ClassName"/>ResponseCommand(_requestCmd<xsl:if test="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]">, <xsl:apply-templates select="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="direction">O</xsl:with-param></xsl:apply-templates></xsl:if>); + } + } + + public final class <xsl:value-of select="$ClassName"/>ResponseCommand extends QMFMethodResponseCommand + { + <xsl:apply-templates select="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]" mode="methodInputArgDecl"/> + private <xsl:value-of select="$ClassName"/>ResponseCommand(QMFMethodRequestCommand cmd<xsl:if test="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]">, <xsl:apply-templates select="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="includeType">yes</xsl:with-param><xsl:with-param name="direction">O</xsl:with-param></xsl:apply-templates></xsl:if>) + { + super(cmd); + + <xsl:apply-templates select="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]" mode="methodInputArgAssign"/> + } + + @Override + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + + <xsl:apply-templates select="node()[name()='arg' and ( @dir='O' or @dir='IO' ) ]" mode="encodeArg"/> + } + } + + </xsl:template> + <xsl:template match="node()[name()='method']" mode="methodDefinition"><xsl:param name="qmfClass"/><xsl:param name="delegate">N</xsl:param> + <xsl:variable name="ClassName"><xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>Method</xsl:variable><xsl:text> + </xsl:text><xsl:if test="$delegate='N'">public </xsl:if><xsl:value-of select="$qmfClass"/>Class.<xsl:value-of select="$ClassName"/>ResponseCommand <xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>(<xsl:value-of select="$qmfClass"/>Class.<xsl:value-of select="$ClassName"/>ResponseCommandFactory factory<xsl:if test="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">, <xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="includeType">yes</xsl:with-param></xsl:apply-templates> </xsl:if>)<xsl:if test="$delegate='N'"> + { + return getDelegate().<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>(factory<xsl:if test="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">, <xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"/></xsl:if> ); + } + </xsl:if><xsl:if test="$delegate='Y'">;</xsl:if> + </xsl:template> + <xsl:template match="node()[name()='arg']" mode="argument"> + QMFMethod.Argument <xsl:value-of select="@name"/> = new QMFMethod.Argument("<xsl:value-of select="@name"/>", QMFType.<xsl:call-template name="qmfType"><xsl:with-param name="type" select="@type"/></xsl:call-template>); +<xsl:if test="@desc"> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/>.setDescription("<xsl:value-of select="@desc" disable-output-escaping="yes"/>"); +</xsl:if> +<xsl:if test="@dir"> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/>.setDirection(QMFMethod.Direction.<xsl:value-of select="@dir"/>); </xsl:if> + addArgument( <xsl:value-of select="@name"/> ); + </xsl:template> + <xsl:template match="node()[name()='arg']" mode="decodeArg"> + <xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"></xsl:with-param></xsl:call-template><xsl:text> </xsl:text><xsl:value-of select="@name"/> = decoder.<xsl:call-template name="decoderRead"><xsl:with-param name="type" select="@type"/></xsl:call-template>; + </xsl:template> + <xsl:template match="node()[name()='arg']" mode="encodeArg"> + encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="type" select="@type"/><xsl:with-param name="var">_<xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>; + </xsl:template> + <xsl:template match="node()[name()='arg']" mode="methodArgList"><xsl:param name="includeType"/><xsl:param name="direction">I</xsl:param><xsl:param name="prefix"></xsl:param> + <xsl:if test="$includeType"><xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"/></xsl:call-template></xsl:if><xsl:text> </xsl:text><xsl:value-of select="$prefix"/><xsl:value-of select="@name"/><xsl:if test="following-sibling::node()[name()='arg' and ( @dir=$direction or @dir='IO' ) ]">, </xsl:if> + </xsl:template> + <xsl:template match="node()[name()='arg']" mode="methodInputArgDecl"> + private final <xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"/></xsl:call-template> _<xsl:value-of select="@name"/>; + </xsl:template> + <xsl:template match="node()[name()='arg']" mode="methodInputArgAssign"> + _<xsl:value-of select="@name"/> = <xsl:value-of select="@name"/>; + </xsl:template> + + <xsl:template match="node()[name()='class']" mode="classList">_<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>Class<xsl:if test="following-sibling::node()[name()='class']">, </xsl:if></xsl:template> + <xsl:template match="node()[name()='event']" mode="eventList">_<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>EventClass<xsl:if test="following-sibling::node()[name()='event']">, </xsl:if></xsl:template> + <xsl:template match="node()[name()='property']" mode="propertyList">_<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>Property<xsl:if test="following-sibling::node()[name()='property']">, </xsl:if></xsl:template> + <xsl:template match="node()[name()='statistic']" mode="statisticList"><xsl:variable name="field">_<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template></xsl:variable><xsl:choose><xsl:when test="@type!='mmaTime'"><xsl:value-of select="$field"/>Statistic<xsl:if test="@type='hilo32'">, <xsl:value-of select="$field"/>HighStatistic, <xsl:value-of select="$field"/>LowStatistic</xsl:if></xsl:when><xsl:otherwise><xsl:value-of select="$field"/>SamplesStatistic, <xsl:value-of select="$field"/>MaxStatistic, <xsl:value-of select="$field"/>MinStatistic, <xsl:value-of select="$field"/>AverageStatistic</xsl:otherwise></xsl:choose><xsl:if test="following-sibling::node()[name()='statistic']">, </xsl:if></xsl:template> + <xsl:template match="node()[name()='method']" mode="methodList">_<xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template>Method<xsl:if test="following-sibling::node()[name()='method']">, </xsl:if></xsl:template> + + + <xsl:template match="node()[name()='event']" mode="event"> + <xsl:variable name="ClassName"><xsl:call-template name="initCap"><xsl:with-param name="input" select="@name"/></xsl:call-template>EventClass</xsl:variable> + <xsl:variable name="cmdName"><xsl:call-template name="initCap"><xsl:with-param name="input" select="@name"/></xsl:call-template>Event</xsl:variable> + <xsl:variable name="name"><xsl:call-template name="initLower"><xsl:with-param name="input" select="@name"/></xsl:call-template></xsl:variable> + + <xsl:variable name="argsList"><xsl:call-template name="argList"><xsl:with-param name="args" select="@args"></xsl:with-param></xsl:call-template></xsl:variable> + + public class <xsl:value-of select="$ClassName"/> extends QMFEventClass + { +<!-- <xsl:apply-templates select="node()[name()='property']" mode="property"/> --> + + <xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/></xsl:apply-templates> + + private <xsl:value-of select="$ClassName"/>() + { + super("<xsl:value-of select="$name"/>", + new byte[16]); + + setProperties( Arrays.asList( new QMFProperty[] { <xsl:value-of select="$argsList"/> } ) ); + } + + public QMFEventSeverity getSeverity() + { + return QMFEventSeverity.<xsl:call-template name="severity"><xsl:with-param name="severity" select="@sev"/></xsl:call-template>; + } + + public QMFEventCommand<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="$ClassName"/><xsl:text disable-output-escaping="yes">></xsl:text> newEvent(<xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/><xsl:with-param name="tmpl">argParamList</xsl:with-param><xsl:with-param name="separator">, </xsl:with-param></xsl:apply-templates>) + { + return new <xsl:value-of select="$cmdName"/>(<xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/><xsl:with-param name="tmpl">argList</xsl:with-param><xsl:with-param name="separator">, </xsl:with-param></xsl:apply-templates>); + } + + + + } + + private final <xsl:value-of select="$ClassName"/> _<xsl:value-of select="$name"/>EventClass = new <xsl:value-of select="$ClassName"/>(); + + private final class <xsl:value-of select="$cmdName"/> extends QMFEventCommand<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="$ClassName"/><xsl:text disable-output-escaping="yes">></xsl:text> + { + <xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/><xsl:with-param name="tmpl">argMemberDef</xsl:with-param></xsl:apply-templates> + + private <xsl:value-of select="$cmdName"/>(<xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/><xsl:with-param name="tmpl">argParamList</xsl:with-param><xsl:with-param name="separator">, </xsl:with-param></xsl:apply-templates>) + { + <xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/><xsl:with-param name="tmpl">argMemberAssign</xsl:with-param></xsl:apply-templates> + } + + public <xsl:value-of select="$ClassName"/> getEventClass() + { + return _<xsl:value-of select="$name"/>EventClass; + } + + public void encode(final BBEncoder encoder) + { + super.encode(encoder); + <xsl:apply-templates select="preceding-sibling::node()[name()='eventArguments']" mode="eventArg"><xsl:with-param name="args" select="@args"/><xsl:with-param name="tmpl">argEncode</xsl:with-param><xsl:with-param name="separator"><xsl:text> + </xsl:text></xsl:with-param></xsl:apply-templates> + + } + } + </xsl:template> + + <xsl:template name="eventArguments" mode="eventArg" match="node()[name()='eventArguments']"> + <xsl:param name="args"></xsl:param> + <xsl:param name="tmpl">propertyClass</xsl:param> + <xsl:param name="separator"></xsl:param> + <xsl:variable name="arg"><xsl:choose> + <xsl:when test="contains($args,',')"><xsl:value-of select="normalize-space(substring-before($args,','))"/></xsl:when> + <xsl:otherwise><xsl:value-of select="$args"/></xsl:otherwise> + </xsl:choose></xsl:variable> + <xsl:variable name="tail" select="normalize-space(substring-after($args,','))"></xsl:variable> + <xsl:if test="string-length($arg)>0"> + <xsl:apply-templates mode="eventArg" select="node()[name()='arg' and @name=$arg]"><xsl:with-param name="tmpl" select="$tmpl"/></xsl:apply-templates> + </xsl:if> + <xsl:if test="string-length($tail)>0"><xsl:value-of select="$separator"/><xsl:apply-templates select="." mode="eventArg"><xsl:with-param name="args" select="$tail"/><xsl:with-param name="tmpl" select="$tmpl"/><xsl:with-param name="separator" select="$separator"/></xsl:apply-templates></xsl:if> + </xsl:template> + + <xsl:template mode="eventArg" match="node()[name()='arg']"> + <xsl:param name="tmpl"/> + <xsl:choose> + <xsl:when test="$tmpl='propertyClass'"><xsl:apply-templates mode="propertyClass" select="."/></xsl:when> + </xsl:choose> + <xsl:choose> + <xsl:when test="$tmpl='argParamList'"><xsl:apply-templates mode="argParamList" select="."/></xsl:when> + </xsl:choose> + <xsl:choose> + <xsl:when test="$tmpl='argList'"><xsl:apply-templates mode="argList" select="."/></xsl:when> + </xsl:choose> + <xsl:choose> + <xsl:when test="$tmpl='argMemberDef'"><xsl:apply-templates mode="argMemberDef" select="."/></xsl:when> + </xsl:choose> + <xsl:choose> + <xsl:when test="$tmpl='argMemberAssign'"><xsl:apply-templates mode="argMemberAssign" select="."/></xsl:when> + </xsl:choose> + <xsl:choose> + <xsl:when test="$tmpl='argEncode'"><xsl:apply-templates mode="argEncode" select="."/></xsl:when> + </xsl:choose> + </xsl:template> + + <xsl:template name="arg" mode="propertyClass" match="node()[name()='arg']"> +<xsl:variable name="propClassName"><xsl:call-template name="initCap"><xsl:with-param name="input" select="@name"/></xsl:call-template>Arg</xsl:variable> + public class <xsl:value-of select="$propClassName"/> extends QMFProperty + { + private <xsl:value-of select="$propClassName"/>() + { + super( "<xsl:value-of select="@name"/>", + QMFType.<xsl:call-template name="qmfType"><xsl:with-param name="type" select="@type"></xsl:with-param></xsl:call-template>, + QMFProperty.AccessCode.RO,false,false); + + <xsl:if test="@desc"> + setDescription("<xsl:value-of select="@desc"/>"); + </xsl:if> + } + } + + private final <xsl:value-of select="$propClassName"/> _<xsl:value-of select="@name"/>Arg = new <xsl:value-of select="$propClassName"/>(); + </xsl:template> + + <xsl:template mode="argMemberDef" match="node()[name()='arg']"><xsl:text> + private final </xsl:text><xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"></xsl:with-param></xsl:call-template><xsl:text> _</xsl:text><xsl:value-of select="@name"/>;</xsl:template> + <xsl:template mode="argParamList" match="node()[name()='arg']"><xsl:call-template name="javaType"><xsl:with-param name="type" select="@type"/></xsl:call-template><xsl:text> </xsl:text><xsl:value-of select="@name"/></xsl:template> + <xsl:template mode="argList" match="node()[name()='arg']"><xsl:value-of select="@name"/></xsl:template> + <xsl:template mode="argMemberAssign" match="node()[name()='arg']"><xsl:text> + _</xsl:text><xsl:value-of select="@name"/> = <xsl:value-of select="@name"/>;</xsl:template> + <xsl:template mode="argEncode" match="node()[name()='arg']">encoder.<xsl:call-template name="encoderWrite"><xsl:with-param name="type" select="@type"/><xsl:with-param name="var">_<xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>;</xsl:template> + + <xsl:template name="argList"> + <xsl:param name="args"/> + <xsl:variable name="arg"><xsl:choose> + <xsl:when test="contains($args,',')"><xsl:value-of select="normalize-space(substring-before($args,','))"/></xsl:when> + <xsl:otherwise><xsl:value-of select="$args"/></xsl:otherwise> + </xsl:choose></xsl:variable> + <xsl:variable name="tail" select="normalize-space(substring-after($args,','))"></xsl:variable> + <xsl:if test="string-length($arg)>0">_<xsl:value-of select="$arg"/>Arg</xsl:if> + <xsl:if test="string-length($tail)>0">, <xsl:call-template name="argList"><xsl:with-param name="args" select="$tail"/></xsl:call-template></xsl:if> + </xsl:template> + + + <xsl:template name="qmfType"><xsl:param name="type"/> +<xsl:choose><xsl:when test="$type='absTime'">ABSTIME</xsl:when> +<xsl:when test="$type='bool'">BOOLEAN</xsl:when> +<xsl:when test="$type='map'">MAP</xsl:when> +<xsl:when test="$type='objId'">OBJECTREFERENCE</xsl:when> +<xsl:when test="$type='sstr'">STR8</xsl:when> +<xsl:when test="$type='lstr'">STR16</xsl:when> +<xsl:when test="$type='uint16'">UINT16</xsl:when> +<xsl:when test="$type='uint32'">UINT32</xsl:when> +<xsl:when test="$type='uuid'">UUID</xsl:when> +<xsl:when test="$type='deltaTime'">DELTATIME</xsl:when> +<xsl:when test="$type='count32'">UINT32</xsl:when> +<xsl:when test="$type='count64'">UINT64</xsl:when> + <xsl:otherwise><xsl:value-of select="$type"/></xsl:otherwise> +</xsl:choose> +</xsl:template> + + + <xsl:template name="javaType"><xsl:param name="type"/><xsl:param name="referenceType">UUID</xsl:param> + <xsl:choose><xsl:when test="$type='absTime'">Long</xsl:when> + <xsl:when test="$type='bool'">Boolean</xsl:when> + <xsl:when test="$type='map'">Map</xsl:when> + <xsl:when test="$type='objId'"><xsl:value-of select="$referenceType"/>Object</xsl:when> + <xsl:when test="$type='sstr'">String</xsl:when> + <xsl:when test="$type='lstr'">String</xsl:when> + <xsl:when test="$type='uint16'">Integer</xsl:when> + <xsl:when test="$type='uint32'">Long</xsl:when> + <xsl:when test="$type='uuid'">UUID</xsl:when> + <xsl:when test="$type='deltaTime'">Long</xsl:when> + <xsl:when test="$type='count32'">Long</xsl:when> + <xsl:when test="$type='count64'">Long</xsl:when> + <xsl:otherwise><xsl:value-of select="$type"/></xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="encoderWrite"><xsl:param name="type"/><xsl:param name="var"/> + <xsl:choose><xsl:when test="$type='absTime'">writeUint64( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='bool'">writeInt8( <xsl:value-of select="$var"/> ? (byte) -1 : (byte) 0)</xsl:when> + <xsl:when test="$type='map'">writeMap( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='objId'">writeBin128( <xsl:value-of select="$var"/>.getId() )</xsl:when> + <xsl:when test="$type='sstr'">writeStr8( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='lstr'">writeStr16( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='uint16'">writeUint16( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='uint32'">writeUint32( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='uuid'">writeUuid( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='deltaTime'">writeUint64( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='count32'">writeUint32( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:when test="$type='count64'">writeUint64( <xsl:value-of select="$var"/> )</xsl:when> + <xsl:otherwise><xsl:value-of select="$type"/></xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="decoderRead"><xsl:param name="type"/> + <xsl:choose><xsl:when test="$type='absTime'">readUint64()</xsl:when> + <xsl:when test="$type='bool'">readInt8() != 0</xsl:when> + <xsl:when test="$type='map'">readMap()</xsl:when> + <xsl:when test="$type='objId'">readBin128()</xsl:when> + <xsl:when test="$type='sstr'">readStr8()</xsl:when> + <xsl:when test="$type='lstr'">readStr16()</xsl:when> + <xsl:when test="$type='uint16'">readUint16()</xsl:when> + <xsl:when test="$type='uint32'">readUint32()</xsl:when> + <xsl:when test="$type='uuid'">readUuid()</xsl:when> + <xsl:when test="$type='deltaTime'">readUint64()</xsl:when> + <xsl:when test="$type='count32'">readUint32()</xsl:when> + <xsl:when test="$type='count64'">readUint64()</xsl:when> + <xsl:otherwise><xsl:value-of select="$type"/></xsl:otherwise> + </xsl:choose> + </xsl:template> + + +<xsl:template name="severity"> + <xsl:param name="severity"/> + <xsl:choose> + <xsl:when test="$severity='emerg'">EMERGENCY</xsl:when> + <xsl:when test="$severity='alert'">ALERT</xsl:when> + <xsl:when test="$severity='crit'">CRITICAL</xsl:when> + <xsl:when test="$severity='error'">ERROR</xsl:when> + <xsl:when test="$severity='warn'">WARN</xsl:when> + <xsl:when test="$severity='notice'">NOTICE</xsl:when> + <xsl:when test="$severity='inform'">INFORM</xsl:when> + <xsl:when test="$severity='debug'">DEBUG</xsl:when> + </xsl:choose> + +</xsl:template> + +<xsl:template name="substringAfterLast"><xsl:param name="input"/><xsl:param name="arg"/> +<xsl:choose> + <xsl:when test="contains($input,$arg)"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input"><xsl:value-of select="substring-after($input,$arg)"/></xsl:with-param><xsl:with-param name="arg"><xsl:value-of select="$arg"/></xsl:with-param></xsl:call-template></xsl:when> + <xsl:otherwise><xsl:value-of select="$input"/></xsl:otherwise> +</xsl:choose> +</xsl:template> +<xsl:template name="initCap"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:value-of select="substring($input,2)"/></xsl:template> +<xsl:template name="initLower"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/><xsl:value-of select="substring($input,2)"/></xsl:template> +<xsl:template name="toUpper"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:template> +</xsl:stylesheet> diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java index 3f2c1af5c2..311ef1f486 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java @@ -47,6 +47,8 @@ public abstract class AMQDestination implements Destination, Referenceable protected final boolean _isAutoDelete; + private final boolean _browseOnly; + private AMQShortString _queueName; private AMQShortString _routingKey; @@ -82,6 +84,7 @@ public abstract class AMQDestination implements Destination, Referenceable _isExclusive = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_EXCLUSIVE)); _isAutoDelete = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_AUTODELETE)); _isDurable = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_DURABLE)); + _browseOnly = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_BROWSE)); _queueName = binding.getQueueName() == null ? null : binding.getQueueName(); _routingKey = binding.getRoutingKey() == null ? null : binding.getRoutingKey(); _bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys(); @@ -122,6 +125,12 @@ public abstract class AMQDestination implements Destination, Referenceable protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive, boolean isAutoDelete, AMQShortString queueName, boolean isDurable,AMQShortString[] bindingKeys) { + this (exchangeName, exchangeClass, routingKey, isExclusive,isAutoDelete,queueName,isDurable,bindingKeys, false); + } + + protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive, + boolean isAutoDelete, AMQShortString queueName, boolean isDurable,AMQShortString[] bindingKeys, boolean browseOnly) + { if ( (ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(exchangeClass) || ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(exchangeClass)) && routingKey == null) @@ -144,6 +153,7 @@ public abstract class AMQDestination implements Destination, Referenceable _queueName = queueName; _isDurable = isDurable; _bindingKeys = bindingKeys == null || bindingKeys.length == 0 ? new AMQShortString[0] : bindingKeys; + _browseOnly = browseOnly; } public AMQShortString getEncodedName() @@ -502,4 +512,9 @@ public abstract class AMQDestination implements Destination, Referenceable return new AMQAnyDestination(binding); } } + + public boolean isBrowseOnly() + { + return _browseOnly; + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java index a9142ff4e4..9f934d1055 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java @@ -20,52 +20,14 @@ */ package org.apache.qpid.client; -import java.io.Serializable; -import java.net.URISyntaxException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.jms.BytesMessage; -import javax.jms.Destination; -import javax.jms.IllegalStateException; -import javax.jms.InvalidDestinationException; -import javax.jms.InvalidSelectorException; -import javax.jms.JMSException; -import javax.jms.MapMessage; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.jms.ObjectMessage; -import javax.jms.Queue; -import javax.jms.QueueBrowser; -import javax.jms.QueueReceiver; -import javax.jms.QueueSender; -import javax.jms.QueueSession; -import javax.jms.StreamMessage; -import javax.jms.TemporaryQueue; -import javax.jms.TemporaryTopic; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicPublisher; -import javax.jms.TopicSession; -import javax.jms.TopicSubscriber; -import javax.jms.TransactionRolledBackException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.qpid.AMQChannelClosedException; import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQInvalidArgumentException; import org.apache.qpid.AMQInvalidRoutingKeyException; -import org.apache.qpid.AMQChannelClosedException; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverNoopSupport; import org.apache.qpid.client.failover.FailoverProtectedOperation; @@ -92,8 +54,23 @@ import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.jms.Session; import org.apache.qpid.thread.Threading; import org.apache.qpid.url.AMQBindingURL; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import javax.jms.*; +import javax.jms.IllegalStateException; +import java.io.Serializable; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /** * <p/><table id="crc"><caption>CRC Card</caption> @@ -734,7 +711,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic } - //if we don't have an exception then we can perform closing operations + //if we don't have an exception then we can perform closing operations _closing.set(e == null); if (!_closed.getAndSet(true)) @@ -905,7 +882,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), null, null, - false, false); + ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public C createExclusiveConsumer(Destination destination) throws JMSException @@ -913,7 +890,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, true, null, null, - false, false); + ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException @@ -921,7 +898,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, false, (destination instanceof Topic), - messageSelector, null, false, false); + messageSelector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) @@ -930,7 +907,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic checkValidDestination(destination); return createConsumerImpl(destination, _prefetchHighMark, _prefetchLowMark, noLocal, (destination instanceof Topic), - messageSelector, null, false, false); + messageSelector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createExclusiveConsumer(Destination destination, String messageSelector, boolean noLocal) @@ -947,7 +924,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkValidDestination(destination); - return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, null, false, false); + return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, int prefetchHigh, int prefetchLow, boolean noLocal, @@ -955,7 +932,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkValidDestination(destination); - return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, null, false, false); + return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, null, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, int prefetch, boolean noLocal, boolean exclusive, @@ -963,7 +940,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkValidDestination(destination); - return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, rawSelector, false, false); + return createConsumerImpl(destination, prefetch, prefetch / 2, noLocal, exclusive, selector, rawSelector, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } public MessageConsumer createConsumer(Destination destination, int prefetchHigh, int prefetchLow, boolean noLocal, @@ -971,7 +948,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic { checkValidDestination(destination); - return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, rawSelector, false, + return createConsumerImpl(destination, prefetchHigh, prefetchLow, noLocal, exclusive, selector, rawSelector, ((destination instanceof AMQDestination) && ((AMQDestination)destination).isBrowseOnly()), false); } @@ -1526,7 +1503,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic sendRecover(); markClean(); - + if (!isSuspended) { suspendChannel(false); @@ -1599,7 +1576,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic // should be rolled back(reject/release) _rollbackMark.set(_highestDeliveryTag.get()); - syncDispatchQueue(); + syncDispatchQueue(); _dispatcher.rollback(); diff --git a/qpid/java/common/build.xml b/qpid/java/common/build.xml index 44cc19aa07..69b241b7e6 100644 --- a/qpid/java/common/build.xml +++ b/qpid/java/common/build.xml @@ -27,6 +27,7 @@ <property name="gentools.home" location="${project.root}/../gentools" /> <property name="generated.package" value="org/apache/qpid/framing" /> <property name="generated.dir" location="${module.precompiled}/${generated.package}" /> + <property name="qpidbuildversion.java" location="${module.precompiled}/org/apache/qpid/QpidBuildVersion.java" /> <property name="xml.spec.dir" location="${project.root}/../specs" /> <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml amqp0-9-1.stripped.xml" /> <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml ${xml.spec.dir}/amqp0-9-1.stripped.xml" /> @@ -77,7 +78,26 @@ <touch file="${gentools.timestamp}" /> </target> - <target name="precompile" depends="gentools,jython,create-version"/> + <target name="build-version" depends="create-version" if="version-stale"> + <tstamp> + <format property="build.time" pattern="yyyy-MM-dd HH:mm:ss z" timezone="UTC"/> + </tstamp> + + <echo file="${qpidbuildversion.java}" append="false">package org.apache.qpid; + +public class QpidBuildVersion +{ + public static final String VERSION = "${project.version}"; + public static final String SVN_VERSION = "${svnversion.output}"; + public static final String BUILD_PROJECT = "${project.name}"; + public static final String BUILD_TIME = "${build.time}"; + +} +</echo> + + </target> + + <target name="precompile" depends="gentools,jython,create-version,build-version"/> <target name="bundle" depends="bundle-tasks"/> </project> diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java index a8e7f47db0..39a9beb9e8 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java @@ -40,8 +40,6 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt private static final byte MINUS = (byte)'-'; private static final byte ZERO = (byte) '0'; - - private final class TokenizerImpl implements AMQShortStringTokenizer { private final byte _delim; @@ -115,7 +113,7 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt private final int _length; private static final char[] EMPTY_CHAR_ARRAY = new char[0]; - + public static final AMQShortString EMPTY_STRING = new AMQShortString((String)null); public AMQShortString(byte[] data) @@ -760,6 +758,11 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt return false; //To change body of created methods use File | Settings | File Templates. } + public static AMQShortString valueOf(Object obj) + { + return obj == null ? null : new AMQShortString(String.valueOf(obj)); + } + public static void main(String args[]) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java index 341238c667..bd566adf8f 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java @@ -21,15 +21,15 @@ package org.apache.qpid.framing; import org.apache.mina.common.ByteBuffer; - -import org.apache.qpid.AMQPInvalidClassException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.qpid.AMQPInvalidClassException; + import java.math.BigDecimal; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -68,8 +68,11 @@ public class FieldTable public FieldTable(ByteBuffer buffer, long length) throws AMQFrameDecodingException { this(); - _encodedForm = buffer.slice(); - _encodedForm.limit((int) length); + ByteBuffer encodedForm = buffer.slice(); + encodedForm.limit((int) length); + _encodedForm = ByteBuffer.allocate((int)length); + _encodedForm.put(encodedForm); + _encodedForm.flip(); _encodedSize = length; buffer.skip((int) length); } @@ -829,6 +832,36 @@ public class FieldTable recalculateEncodedSize(); } + public static Map<String, Object> convertToMap(final FieldTable fieldTable) + { + final Map<String, Object> map = new HashMap<String, Object>(); + + if(fieldTable != null) + { + fieldTable.processOverElements( + new FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + Object val = value.getValue(); + if(val instanceof AMQShortString) + { + val = val.toString(); + } + map.put(propertyName, val); + return true; + } + + public Object getResult() + { + return map; + } + }); + } + return map; + } + public static interface FieldTableElementProcessor { @@ -1046,6 +1079,9 @@ public class FieldTable { final AMQShortString key = EncodingUtils.readAMQShortString(buffer); + + _logger.debug("FieldTable::PropFieldTable(buffer," + length + "): Read key '" + key); + AMQTypedValue value = AMQTypedValue.readFromBuffer(buffer); if (trace) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java index 94869ab205..70d7d2c6b2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java @@ -3,6 +3,17 @@ package org.apache.qpid.thread; public class DefaultThreadFactory implements ThreadFactory { + private static class QpidThread extends Thread + { + private QpidThread(final Runnable target) + { + super(target); + } + + } + + + public Thread createThread(Runnable r) { return new Thread(r); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java index b12fbb75e6..74064c9d11 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java @@ -20,8 +20,19 @@ */ package org.apache.qpid.transport; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSManager; +import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; + +import org.apache.qpid.security.UsernamePasswordCallbackHandler; import static org.apache.qpid.transport.Connection.State.OPEN; +import org.apache.qpid.transport.util.Logger; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.ArrayList; @@ -30,18 +41,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -import org.apache.qpid.security.UsernamePasswordCallbackHandler; -import org.apache.qpid.transport.util.Logger; -import org.ietf.jgss.GSSContext; -import org.ietf.jgss.GSSException; -import org.ietf.jgss.GSSManager; -import org.ietf.jgss.GSSName; -import org.ietf.jgss.Oid; - /** * ClientDelegate @@ -54,20 +53,22 @@ public class ClientDelegate extends ConnectionDelegate private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2"; protected static Oid KRB5_OID; - - static { - try { + + static + { + try + { KRB5_OID = new Oid(KRB5_OID_STR); } catch (GSSException ignore) {} } - + private List<String> clientMechs; private ConnectionSettings conSettings; - + public ClientDelegate(ConnectionSettings settings) { this.conSettings = settings; - this.clientMechs = Arrays.asList(settings.getSaslMechs().split(" ")); + this.clientMechs = Arrays.asList(settings.getSaslMechs().split(" ")); } public void init(Connection conn, ProtocolHeader hdr) @@ -81,12 +82,17 @@ public class ClientDelegate extends ConnectionDelegate @Override public void connectionStart(Connection conn, ConnectionStart start) { Map<String,Object> clientProperties = new HashMap<String,Object>(); + + if(this.conSettings.getClientProperties() != null) + { + clientProperties.putAll(this.conSettings.getClientProperties()); + } + clientProperties.put("qpid.session_flow", 1); clientProperties.put("qpid.client_pid",getPID()); - clientProperties.put("qpid.client_pid",clientProperties.get("qpid.client_pid")); clientProperties.put("qpid.client_process", System.getProperty("qpid.client_process","Qpid Java Client")); - + List<Object> brokerMechs = start.getMechanisms(); if (brokerMechs == null || brokerMechs.isEmpty()) { @@ -94,27 +100,29 @@ public class ClientDelegate extends ConnectionDelegate (clientProperties, null, null, conn.getLocale()); return; } - + List<String> choosenMechs = new ArrayList<String>(); for (String mech:clientMechs) { - if (brokerMechs.contains(mech)) + if (brokerMechs.contains(mech)) { choosenMechs.add(mech); } } - + if (choosenMechs.size() == 0) { conn.exception(new ConnectionException("The following SASL mechanisms " + - clientMechs.toString() + + clientMechs.toString() + " specified by the client are not supported by the broker")); return; } - + String[] mechs = new String[choosenMechs.size()]; - choosenMechs.toArray(mechs); - + choosenMechs.toArray(mechs); + + conn.setServerProperties(start.getServerProperties()); + try { Map<String,Object> saslProps = new HashMap<String,Object>(); @@ -162,8 +170,8 @@ public class ClientDelegate extends ConnectionDelegate tune.getHeartbeatMin(), tune.getHeartbeatMax() ); - conn.connectionTuneOk(tune.getChannelMax(), - tune.getMaxFrameSize(), + conn.connectionTuneOk(tune.getChannelMax(), + tune.getMaxFrameSize(), hb_interval); // The idle timeout is twice the heartbeat amount (in milisecs) conn.setIdleTimeout(hb_interval*1000*2); @@ -212,11 +220,11 @@ public class ClientDelegate extends ConnectionDelegate return max; } } - + private int getPID() { RuntimeMXBean rtb = ManagementFactory.getRuntimeMXBean(); - String processName = rtb.getName(); + String processName = rtb.getName(); if (processName != null && processName.indexOf('@')>0) { try @@ -236,36 +244,36 @@ public class ClientDelegate extends ConnectionDelegate } } - + private String getUserID() { log.debug("Obtaining userID from kerberos"); String service = conSettings.getSaslProtocol() + "@" + conSettings.getSaslServerName(); GSSManager manager = GSSManager.getInstance(); - - try + + try { GSSName acceptorName = manager.createName(service, GSSName.NT_HOSTBASED_SERVICE, KRB5_OID); - + GSSContext secCtx = manager.createContext(acceptorName, KRB5_OID, null, GSSContext.INDEFINITE_LIFETIME); - - secCtx.initSecContext(new byte[0], 0, 1); - + + secCtx.initSecContext(new byte[0], 0, 1); + if (secCtx.getSrcName() != null) { return secCtx.getSrcName().toString(); - } - - } - catch (GSSException e) + } + + } + catch (GSSException e) { log.warn("Unable to retrieve userID from Kerberos due to error",e); } - + return null; } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java index 17a13561c8..8c2da9d77a 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java @@ -20,24 +20,26 @@ */ package org.apache.qpid.transport; +import static org.apache.qpid.transport.Connection.State.CLOSED; +import static org.apache.qpid.transport.Connection.State.CLOSING; +import static org.apache.qpid.transport.Connection.State.NEW; +import static org.apache.qpid.transport.Connection.State.OPEN; +import static org.apache.qpid.transport.Connection.State.OPENING; import org.apache.qpid.transport.network.ConnectionBinding; import org.apache.qpid.transport.network.io.IoTransport; import org.apache.qpid.transport.util.Logger; import org.apache.qpid.transport.util.Waiter; import org.apache.qpid.util.Strings; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - import java.util.UUID; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslServer; - -import static org.apache.qpid.transport.Connection.State.*; - /** * Connection @@ -55,6 +57,7 @@ public class Connection extends ConnectionInvoker private static final Logger log = Logger.get(Connection.class); + public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD } class DefaultConnectionListener implements ConnectionListener @@ -67,6 +70,24 @@ public class Connection extends ConnectionInvoker public void closed(Connection conn) {} } + public static interface SessionFactory + { + Session newSession(Connection conn, Binary name, long expiry); + } + + private static final class DefaultSessionFactory implements SessionFactory + { + + public Session newSession(final Connection conn, final Binary name, final long expiry) + { + return new Session(conn, name, expiry); + } + } + + private static final SessionFactory DEFAULT_SESSION_FACTORY = new DefaultSessionFactory(); + + private SessionFactory _sessionFactory = DEFAULT_SESSION_FACTORY; + private ConnectionDelegate delegate; private Sender<ProtocolEvent> sender; @@ -76,7 +97,7 @@ public class Connection extends ConnectionInvoker private State state = NEW; final private Object lock = new Object(); private long timeout = 60000; - private List<ConnectionListener> listeners = new ArrayList<ConnectionListener>(); + private List<ConnectionListener> listeners = new ArrayList<ConnectionListener>(); private ConnectionException error = null; private int channelMax = 1; @@ -85,6 +106,7 @@ public class Connection extends ConnectionInvoker private SaslClient saslClient; private int idleTimeout = 0; private String _authorizationID; + private Map<String,Object> _serverProperties; private String userID; private ConnectionSettings conSettings; @@ -111,7 +133,7 @@ public class Connection extends ConnectionInvoker public void setSender(Sender<ProtocolEvent> sender) { this.sender = sender; - sender.setIdleTimeout(idleTimeout); + sender.setIdleTimeout(idleTimeout); } protected void setState(State state) @@ -157,7 +179,7 @@ public class Connection extends ConnectionInvoker { connect(host, port, vhost, username, password, false); } - + public void connect(String host, int port, String vhost, String username, String password, boolean ssl) { connect(host, port, vhost, username, password, ssl,"PLAIN"); @@ -165,6 +187,12 @@ public class Connection extends ConnectionInvoker public void connect(String host, int port, String vhost, String username, String password, boolean ssl,String saslMechs) { + connect(host, port, vhost, username, password, ssl,saslMechs, Collections.EMPTY_MAP); + } + + + public void connect(String host, int port, String vhost, String username, String password, boolean ssl,String saslMechs,Map<String,Object> clientProps) + { ConnectionSettings settings = new ConnectionSettings(); settings.setHost(host); settings.setPort(port); @@ -173,11 +201,13 @@ public class Connection extends ConnectionInvoker settings.setPassword(password); settings.setUseSSL(ssl); settings.setSaslMechs(saslMechs); + settings.setClientProperties(clientProps); connect(settings); } - + public void connect(ConnectionSettings settings) { + synchronized (lock) { conSettings = settings; @@ -185,9 +215,9 @@ public class Connection extends ConnectionInvoker userID = settings.getUsername(); delegate = new ClientDelegate(settings); - IoTransport.connect(settings.getHost(), - settings.getPort(), - ConnectionBinding.get(this), + IoTransport.connect(settings.getHost(), + settings.getPort(), + ConnectionBinding.get(this), settings.isUseSSL()); send(new ProtocolHeader(1, 0, 10)); @@ -264,7 +294,7 @@ public class Connection extends ConnectionInvoker { synchronized (lock) { - Session ssn = new Session(this, name, expiry); + Session ssn = _sessionFactory.newSession(this, name, expiry); sessions.put(name, ssn); map(ssn); ssn.attach(); @@ -280,6 +310,13 @@ public class Connection extends ConnectionInvoker } } + public void setSessionFactory(SessionFactory sessionFactory) + { + assert sessionFactory != null; + + _sessionFactory = sessionFactory; + } + public void setConnectionId(int id) { _connectionId = id; @@ -425,7 +462,7 @@ public class Connection extends ConnectionInvoker { listener.exception(this, e); } - + } public void exception(Throwable t) @@ -481,7 +518,7 @@ public class Connection extends ConnectionInvoker for (ConnectionListener listener: listeners) { listener.closed(this); - } + } } public void close() @@ -545,13 +582,13 @@ public class Connection extends ConnectionInvoker public void setIdleTimeout(int i) { - idleTimeout = i; + idleTimeout = i; if (sender != null) - { - sender.setIdleTimeout(i); + { + sender.setIdleTimeout(i); } } - + public int getIdleTimeout() { return idleTimeout; @@ -566,22 +603,32 @@ public class Connection extends ConnectionInvoker { return _authorizationID; } - + public String getUserID() { return userID; } - + public void setUserID(String id) { userID = id; } + public void setServerProperties(final Map<String, Object> serverProperties) + { + _serverProperties = serverProperties == null ? Collections.EMPTY_MAP : serverProperties; + } + + public Map<String, Object> getServerProperties() + { + return _serverProperties; + } + public String toString() { return String.format("conn:%x", System.identityHashCode(this)); } - + public ConnectionSettings getConnectionSettings() { return conSettings; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java index b25c2d7fd0..c063ef5e6f 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java @@ -20,7 +20,9 @@ */ package org.apache.qpid.transport; -public class ConnectionSettings +import java.util.Map; + +public class ConnectionSettings { String protocol = "tcp"; String host = "localhost"; @@ -32,12 +34,13 @@ public class ConnectionSettings String saslServerName = "localhost"; int port = 5672; int maxChannelCount = 32767; - int maxFrameSize = 65535; + int maxFrameSize = 65535; int heartbeatInterval; boolean useSSL; boolean useSASLEncryption; boolean tcpNodelay; - + private Map<String, Object> _clientProperties; + public boolean isTcpNodelay() { return tcpNodelay; @@ -187,4 +190,14 @@ public class ConnectionSettings { this.maxFrameSize = maxFrameSize; } + + public void setClientProperties(final Map<String, Object> clientProperties) + { + _clientProperties = clientProperties; + } + + public Map<String, Object> getClientProperties() + { + return _clientProperties; + } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java index 818bb19c08..d9a8e5550c 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java @@ -21,27 +21,32 @@ package org.apache.qpid.transport; +import static org.apache.qpid.transport.Option.COMPLETED; +import static org.apache.qpid.transport.Option.SYNC; +import static org.apache.qpid.transport.Option.TIMELY_REPLY; +import static org.apache.qpid.transport.Session.State.CLOSED; +import static org.apache.qpid.transport.Session.State.CLOSING; +import static org.apache.qpid.transport.Session.State.DETACHED; +import static org.apache.qpid.transport.Session.State.NEW; +import static org.apache.qpid.transport.Session.State.OPEN; +import static org.apache.qpid.transport.Session.State.RESUMING; import org.apache.qpid.transport.network.Frame; - +import static org.apache.qpid.transport.util.Functions.mod; import org.apache.qpid.transport.util.Logger; import org.apache.qpid.transport.util.Waiter; +import static org.apache.qpid.util.Serial.ge; +import static org.apache.qpid.util.Serial.gt; +import static org.apache.qpid.util.Serial.le; +import static org.apache.qpid.util.Serial.lt; +import static org.apache.qpid.util.Serial.max; +import static org.apache.qpid.util.Strings.toUTF8; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import static org.apache.qpid.transport.Option.*; -import static org.apache.qpid.transport.Session.State.*; -import static org.apache.qpid.transport.util.Functions.*; -import static org.apache.qpid.util.Serial.*; -import static org.apache.qpid.util.Strings.*; - /** * Session * @@ -140,7 +145,7 @@ public class Session extends SessionInvoker this.expiry = expiry; } - int getChannel() + public int getChannel() { return channel; } @@ -464,7 +469,7 @@ public class Session extends SessionInvoker { commandBytes -= m.getBodySize(); m.complete(); - commands[idx] = null; + commands[idx] = null; } } if (le(lower, maxComplete + 1)) @@ -644,7 +649,7 @@ public class Session extends SessionInvoker m.setSync(true); } needSync = !m.isSync(); - + try { send(m); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java index d18a0f64db..4486b03a67 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java @@ -23,6 +23,7 @@ package org.apache.qpid.transport.codec; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.UUID; /** @@ -315,6 +316,28 @@ public final class BBEncoder extends AbstractEncoder } } + public void writeBin128(UUID id) + { + byte[] data = new byte[16]; + + long msb = id.getMostSignificantBits(); + long lsb = id.getLeastSignificantBits(); + + assert data.length == 16; + for (int i=7; i>=0; i--) + { + data[i] = (byte)(msb & 0xff); + msb = msb >> 8; + } + + for (int i=15; i>=8; i--) + { + data[i] = (byte)(lsb & 0xff); + lsb = (lsb >> 8); + } + writeBin128(data); + } + public void writeFloat(float aFloat) { try diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java index 3759fa238a..ab174b00b3 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java @@ -20,16 +20,6 @@ */ package org.apache.qpid.transport.network; -import static java.lang.Math.min; -import static org.apache.qpid.transport.network.Frame.FIRST_FRAME; -import static org.apache.qpid.transport.network.Frame.FIRST_SEG; -import static org.apache.qpid.transport.network.Frame.HEADER_SIZE; -import static org.apache.qpid.transport.network.Frame.LAST_FRAME; -import static org.apache.qpid.transport.network.Frame.LAST_SEG; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - import org.apache.qpid.transport.Header; import org.apache.qpid.transport.Method; import org.apache.qpid.transport.ProtocolDelegate; @@ -40,6 +30,15 @@ import org.apache.qpid.transport.SegmentType; import org.apache.qpid.transport.Sender; import org.apache.qpid.transport.Struct; import org.apache.qpid.transport.codec.BBEncoder; +import static org.apache.qpid.transport.network.Frame.FIRST_FRAME; +import static org.apache.qpid.transport.network.Frame.FIRST_SEG; +import static org.apache.qpid.transport.network.Frame.HEADER_SIZE; +import static org.apache.qpid.transport.network.Frame.LAST_FRAME; +import static org.apache.qpid.transport.network.Frame.LAST_SEG; + +import static java.lang.Math.min; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** @@ -55,7 +54,7 @@ public final class Disassembler implements Sender<ProtocolEvent>, private final int maxPayload; private final ByteBuffer header; private final Object sendlock = new Object(); - private final ThreadLocal<BBEncoder> encoder = new ThreadLocal() + private final ThreadLocal<BBEncoder> encoder = new ThreadLocal<BBEncoder>() { public BBEncoder initialValue() { @@ -98,7 +97,7 @@ public final class Disassembler implements Sender<ProtocolEvent>, } } - private final void frame(byte flags, byte type, byte track, int channel, int size, ByteBuffer buf) + private void frame(byte flags, byte type, byte track, int channel, int size, ByteBuffer buf) { synchronized (sendlock) { @@ -227,8 +226,14 @@ public final class Disassembler implements Sender<ProtocolEvent>, fragment(flags, type, method, methodSeg); if (payload) { - fragment((byte) 0x0, SegmentType.HEADER, method, headerSeg); - fragment(LAST_SEG, SegmentType.BODY, method, method.getBody()); + ByteBuffer body = method.getBody(); + fragment(body == null ? LAST_SEG : 0x0, SegmentType.HEADER, + method, headerSeg); + if (body != null) + { + fragment(LAST_SEG, SegmentType.BODY, method, body); + } + } } } @@ -237,7 +242,7 @@ public final class Disassembler implements Sender<ProtocolEvent>, { throw new IllegalArgumentException("" + error); } - + public void setIdleTimeout(int i) { sender.setIdleTimeout(i); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java index 6144edb947..e0e06d22ec 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java @@ -60,10 +60,10 @@ final class IoReceiver implements Runnable this.bufferSize = bufferSize; this.socket = transport.getSocket(); this.timeout = timeout; - + try { - receiverThread = Threading.getThreadFactory().createThread(this); + receiverThread = Threading.getThreadFactory().createThread(this); } catch(Exception e) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java index b324cdd5a9..1a2869a815 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java @@ -21,14 +21,8 @@ package org.apache.qpid.transport.network.mina; -import java.io.IOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.ByteBuffer; - import org.apache.mina.common.ConnectFuture; +import org.apache.mina.common.ExecutorThreadModel; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoAcceptor; import org.apache.mina.common.IoConnector; @@ -48,6 +42,9 @@ import org.apache.mina.transport.socket.nio.SocketConnectorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; import org.apache.mina.util.NewThreadExecutor; import org.apache.mina.util.SessionUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.protocol.ProtocolEngineFactory; import org.apache.qpid.ssl.SSLContextFactory; @@ -55,14 +52,19 @@ import org.apache.qpid.thread.QpidThreadExecutor; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.NetworkDriverConfiguration; import org.apache.qpid.transport.OpenException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver { private static final int DEFAULT_BUFFER_SIZE = 32 * 1024; - + ProtocolEngine _protocolEngine; private boolean _useNIO = false; private int _processors = 4; @@ -80,7 +82,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver private WriteFuture _lastWriteFuture; private static final Logger _logger = LoggerFactory.getLogger(MINANetworkDriver.class); - + public MINANetworkDriver(boolean useNIO, int processors, boolean executorPool, boolean protectIO) { _useNIO = useNIO; @@ -100,7 +102,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver _ioSession = session; _ioSession.setAttachment(_protocolEngine); } - + public MINANetworkDriver() { @@ -110,7 +112,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver { _socketConnector = ioConnector; } - + public MINANetworkDriver(IoConnector ioConnector, ProtocolEngine engine) { _socketConnector = ioConnector; @@ -123,7 +125,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver _factory = factory; _config = config; - + if (_useNIO) { _acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(_processors, @@ -135,6 +137,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver } SocketAcceptorConfig sconfig = (SocketAcceptorConfig) _acceptor.getDefaultConfig(); + sconfig.setThreadModel(ExecutorThreadModel.getInstance("MINANetworkDriver(Acceptor)")); SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); if (config != null) @@ -181,12 +184,12 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver { return _ioSession.getRemoteAddress(); } - + public SocketAddress getLocalAddress() { return _ioSession.getLocalAddress(); } - + public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws OpenException @@ -195,7 +198,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver { _sslFactory = sslFactory; } - + if (_useNIO) { _socketConnector = new MultiThreadSocketConnector(1, new QpidThreadExecutor()); @@ -205,7 +208,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver _socketConnector = new SocketConnector(1, new QpidThreadExecutor()); // non-blocking // connector } - + org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers")); // the MINA default is currently to use the pooled allocator although this may change in future // once more testing of the performance of the simple allocator has been done @@ -215,12 +218,23 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver } SocketConnectorConfig cfg = (SocketConnectorConfig) _socketConnector.getDefaultConfig(); - + String s = ""; + StackTraceElement[] trace = Thread.currentThread().getStackTrace(); + for(StackTraceElement elt : trace) + { + if(elt.getClassName().contains("Test")) + { + s = elt.getClassName(); + break; + } + } + cfg.setThreadModel(ExecutorThreadModel.getInstance("MINANetworkDriver(Client)-"+s)); + SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig(); scfg.setTcpNoDelay((config != null) ? config.getTcpNoDelay() : true); scfg.setSendBufferSize((config != null) ? config.getSendBufferSize() : DEFAULT_BUFFER_SIZE); scfg.setReceiveBufferSize((config != null) ? config.getReceiveBufferSize() : DEFAULT_BUFFER_SIZE); - + // Don't have the connector's worker thread wait around for other // connections (we only use // one SocketConnector per connection at the moment anyway). This allows @@ -230,7 +244,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver { ((SocketConnector) _socketConnector).setWorkerTimeout(0); } - + ConnectFuture future = _socketConnector.connect(new InetSocketAddress(destination, port), this, cfg); future.join(); if (!future.isConnected()) @@ -295,7 +309,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver if (_protocolEngine != null) { _protocolEngine.exception(throwable); - } + } else { _logger.error("Exception thrown and no ProtocolEngine to handle it", throwable); @@ -307,12 +321,12 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver * Invoked when a message is received on a particular protocol session. Note * that a protocol session is directly tied to a particular physical * connection. - * + * * @param protocolSession * the protocol session that received the message * @param message * the message itself (i.e. a decoded frame) - * + * * @throws Exception * if the message cannot be processed */ @@ -376,7 +390,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver { _ioSession = protocolSession; } - + if (_acceptingConnections) { // Set up the protocol engine @@ -389,12 +403,12 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver public void sessionIdle(IoSession session, IdleStatus status) throws Exception { if (IdleStatus.WRITER_IDLE.equals(status)) - { + { ((ProtocolEngine) session.getAttachment()).writerIdle(); } else if (IdleStatus.READER_IDLE.equals(status)) { - ((ProtocolEngine) session.getAttachment()).readerIdle(); + ((ProtocolEngine) session.getAttachment()).readerIdle(); } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java b/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java index 25450fea64..9996fff311 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java @@ -31,6 +31,7 @@ public interface BindingURL public static final String OPTION_EXCLUSIVE = "exclusive"; public static final String OPTION_AUTODELETE = "autodelete"; public static final String OPTION_DURABLE = "durable"; + public static final String OPTION_BROWSE = "browse"; public static final String OPTION_CLIENTID = "clientid"; public static final String OPTION_SUBSCRIPTION = "subscription"; public static final String OPTION_ROUTING_KEY = "routingkey"; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java index 1683c5e3d6..458c8b44c3 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java @@ -21,13 +21,14 @@ package org.apache.qpid.server.failover; import junit.framework.TestCase; + import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQConnectionURL; import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.url.URLSyntaxException; import javax.jms.ExceptionListener; @@ -91,7 +92,7 @@ public class FailoverMethodTest extends TestCase implements ExceptionListener // then TCP NoDelay 0 Delay 1 Delay 2 Delay 3 // so 3 delays of 2s in total for connection // as this is a tcp connection it will take 1second per connection to fail - // so max time is 6seconds of delay plus 4 seconds of TCP Delay + 1 second of runtime. == 11 seconds + // so max time is 6seconds of delay plus 4 seconds of TCP Delay + 1 second of runtime. == 11 seconds // Ensure we actually had the delay assertTrue("Failover took less than 6 seconds", duration > 6000); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ConflationQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ConflationQueueTest.java new file mode 100644 index 0000000000..515d93a4e5 --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ConflationQueueTest.java @@ -0,0 +1,435 @@ +/* + * + * 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.qpid.server.queue; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.url.AMQBindingURL; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ConflationQueueTest extends QpidTestCase +{ + private static final int TIMEOUT = 1500; + + + private static final Logger _logger = Logger.getLogger(ConflationQueueTest.class); + + + + protected final String VHOST = "/test"; + protected final String QUEUE = "ConflationQueue"; + + private static final int MSG_COUNT = 400; + + private Connection producerConnection; + private MessageProducer producer; + private Session producerSession; + private Queue queue; + private Connection consumerConnection; + private Session consumerSession; + + + private MessageConsumer consumer; + + protected void setUp() throws Exception + { + super.setUp(); + + producerConnection = getConnection(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + producerConnection.start(); + + + } + + protected void tearDown() throws Exception + { + producerConnection.close(); + consumerConnection.close(); + super.tearDown(); + } + + public void testConflation() throws Exception + { + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.last_value_queue_key","key"); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), false, true, false, arguments); + queue = new org.apache.qpid.client.AMQQueue("amq.direct",QUEUE); + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + producer.send(nextMessage(msg, producerSession)); + } + + producer.close(); + producerSession.close(); + producerConnection.close(); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + Message received; + + List<Message> messages = new ArrayList<Message>(); + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty("msg")); + } + + + } + + + public void testConflationWithRelease() throws Exception + { + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.last_value_queue_key","key"); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), false, true, false, arguments); + queue = new org.apache.qpid.client.AMQQueue("amq.direct",QUEUE); + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT/2; msg++) + { + producer.send(nextMessage(msg, producerSession)); + + } + + // HACK to do something synchronous + ((AMQSession)producerSession).sync(); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + Message received; + List<Message> messages = new ArrayList<Message>(); + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT/2 - 10 + i, msg.getIntProperty("msg")); + } + + consumerSession.close(); + consumerConnection.close(); + + + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + for (int msg = MSG_COUNT/2; msg < MSG_COUNT; msg++) + { + producer.send(nextMessage(msg, producerSession)); + } + + + // HACK to do something synchronous + ((AMQSession)producerSession).sync(); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + messages = new ArrayList<Message>(); + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty("msg")); + } + + } + + + + public void testConflationWithReleaseAfterNewPublish() throws Exception + { + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.last_value_queue_key","key"); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), false, true, false, arguments); + queue = new org.apache.qpid.client.AMQQueue("amq.direct",QUEUE); + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT/2; msg++) + { + producer.send(nextMessage(msg, producerSession)); + } + + // HACK to do something synchronous + ((AMQSession)producerSession).sync(); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + Message received; + List<Message> messages = new ArrayList<Message>(); + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT/2 - 10 + i, msg.getIntProperty("msg")); + } + + consumer.close(); + + for (int msg = MSG_COUNT/2; msg < MSG_COUNT; msg++) + { + producer.send(nextMessage(msg, producerSession)); + } + + // HACK to do something synchronous + ((AMQSession)producerSession).sync(); + + + // this causes the "old" messages to be released + consumerSession.close(); + consumerConnection.close(); + + + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + messages = new ArrayList<Message>(); + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty("msg")); + } + + } + + public void testConflationBrowser() throws Exception + { + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.last_value_queue_key","key"); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), false, true, false, arguments); + queue = new org.apache.qpid.client.AMQQueue("amq.direct",QUEUE); + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + producer.send(nextMessage(msg, producerSession)); + + } + + ((AMQSession)producerSession).sync(); + + AMQBindingURL url = new AMQBindingURL("direct://amq.direct//"+QUEUE+"?browse='true'&durable='true'"); + AMQQueue browseQueue = new AMQQueue(url); + + consumer = consumerSession.createConsumer(browseQueue); + consumerConnection.start(); + Message received; + List<Message> messages = new ArrayList<Message>(); + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty("msg")); + } + + messages.clear(); + + producer.send(nextMessage(MSG_COUNT, producerSession)); + + ((AMQSession)producerSession).sync(); + + while((received = consumer.receive(1000))!=null) + { + messages.add(received); + } + assertEquals("Unexpected number of messages received",1,messages.size()); + assertEquals("Unexpected message number received", MSG_COUNT, messages.get(0).getIntProperty("msg")); + + + producer.close(); + producerSession.close(); + producerConnection.close(); + + + + } + + + public void testConflation2Browsers() throws Exception + { + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.last_value_queue_key","key"); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), false, true, false, arguments); + queue = new org.apache.qpid.client.AMQQueue("amq.direct",QUEUE); + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + producer.send(nextMessage(msg, producerSession)); + + } + + ((AMQSession)producerSession).sync(); + + AMQBindingURL url = new AMQBindingURL("direct://amq.direct//"+QUEUE+"?browse='true'&durable='true'"); + AMQQueue browseQueue = new AMQQueue(url); + + consumer = consumerSession.createConsumer(browseQueue); + MessageConsumer consumer2 = consumerSession.createConsumer(browseQueue); + consumerConnection.start(); + List<Message> messages = new ArrayList<Message>(); + List<Message> messages2 = new ArrayList<Message>(); + Message received = consumer.receive(1000); + Message received2 = consumer2.receive(1000); + + while(received!=null || received2!=null) + { + if(received != null) + { + messages.add(received); + } + if(received2 != null) + { + messages2.add(received2); + } + + + received = consumer.receive(1000); + received2 = consumer2.receive(1000); + + } + + assertEquals("Unexpected number of messages received on first browser",10,messages.size()); + assertEquals("Unexpected number of messages received on second browser",10,messages2.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received on first browser", MSG_COUNT - 10 + i, msg.getIntProperty("msg")); + msg = messages2.get(i); + assertEquals("Unexpected message number received on second browser", MSG_COUNT - 10 + i, msg.getIntProperty("msg")); + } + + + producer.close(); + producerSession.close(); + producerConnection.close(); + + + + } + + + + private Message nextMessage(int msg, Session producerSession) throws JMSException + { + Message send = producerSession.createTextMessage("Message: " + msg); + + send.setStringProperty("key", String.valueOf(msg % 10)); + send.setIntProperty("msg", msg); + + return send; + } + + +} + + diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java index ded2e0913b..395ced436b 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java @@ -24,12 +24,13 @@ package org.apache.qpid.server.queue; import junit.framework.TestCase; import org.apache.log4j.Level; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; import javax.jms.Connection; import javax.jms.ConnectionFactory; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java index d9b0a93132..84ff7055c5 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java @@ -21,12 +21,16 @@ import junit.framework.TestCase; import junit.framework.TestResult; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; +import org.apache.log4j.Level; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.apache.qpid.AMQException; -import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQConnectionFactory; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.transport.TransportConnection; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.jms.BrokerDetails; import org.apache.qpid.jms.ConnectionURL; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -35,9 +39,6 @@ import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.store.DerbyMessageStore; import org.apache.qpid.url.URLSyntaxException; import org.apache.qpid.util.LogMonitor; -import org.apache.log4j.Level; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.jms.Connection; import javax.jms.Destination; @@ -58,7 +59,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.PrintStream; -import java.io.Reader; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; @@ -78,7 +78,7 @@ public class QpidTestCase extends TestCase protected static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class); protected static final int LOGMONITOR_TIMEOUT = 5000; - + protected long RECEIVE_TIMEOUT = 1000l; private Map<String, String> _propertiesSetForTestOnly = new HashMap<String, String>(); @@ -166,7 +166,7 @@ public class QpidTestCase extends TestCase private static final String TEST_OUTPUT = "test.output"; private static final String BROKER_LOG_INTERLEAVE = "broker.log.interleave"; private static final String BROKER_LOG_PREFIX = "broker.log.prefix"; - + // values protected static final String JAVA = "java"; protected static final String CPP = "cpp"; @@ -187,14 +187,14 @@ public class QpidTestCase extends TestCase private Boolean _brokerCleanBetweenTests = Boolean.getBoolean(BROKER_CLEAN_BETWEEN_TESTS); private String _brokerVersion = System.getProperty(BROKER_VERSION, VERSION_08); private String _output = System.getProperty(TEST_OUTPUT); - - private static String _brokerLogPrefix = System.getProperty(BROKER_LOG_PREFIX,"BROKER: "); + + private static String _brokerLogPrefix = System.getProperty(BROKER_LOG_PREFIX,"BROKER: "); protected static boolean _interleaveBrokerLog = Boolean.getBoolean(BROKER_LOG_INTERLEAVE); - + protected File _outputFile; - + protected PrintStream _brokerOutputStream; - + private Map<Integer, Process> _brokers = new HashMap<Integer, Process>(); private InitialContext _initialContext; @@ -216,11 +216,11 @@ public class QpidTestCase extends TestCase public QpidTestCase() { - super("QpidTestCase"); + this("QpidTestCase"); } public void runBare() throws Throwable - { + { _testName = getClass().getSimpleName() + "." + getName(); String qname = getClass().getName() + "." + getName(); @@ -231,7 +231,7 @@ public class QpidTestCase extends TestCase PrintStream oldErr = System.err; PrintStream out = null; PrintStream err = null; - + boolean redirected = _output != null && _output.length() > 0; if (redirected) { @@ -240,15 +240,15 @@ public class QpidTestCase extends TestCase err = new PrintStream(String.format("%s/TEST-%s.err", _output, qname)); System.setOut(out); System.setErr(err); - + if (_interleaveBrokerLog) { - _brokerOutputStream = out; + _brokerOutputStream = out; } else { _brokerOutputStream = new PrintStream(new FileOutputStream(String - .format("%s/TEST-%s.broker.out", _output, qname)), true); + .format("%s/TEST-%s.broker.out", _output, qname)), true); } } @@ -267,7 +267,7 @@ public class QpidTestCase extends TestCase { _logger.error("exception stopping broker", e); } - + if(_brokerCleanBetweenTests) { try @@ -279,7 +279,7 @@ public class QpidTestCase extends TestCase _logger.error("exception cleaning up broker", e); } } - + _logger.info("========== stop " + _testName + " =========="); if (redirected) @@ -289,7 +289,7 @@ public class QpidTestCase extends TestCase err.close(); out.close(); if (!_interleaveBrokerLog) - { + { _brokerOutputStream.close(); } } @@ -380,13 +380,13 @@ public class QpidTestCase extends TestCase { String line; while ((line = in.readLine()) != null) - { + { if (_interleaveBrokerLog) { line = _brokerLogPrefix + line; } out.println(line); - + if (latch != null && line.contains(ready)) { seenReady = true; @@ -433,7 +433,7 @@ public class QpidTestCase extends TestCase */ protected int getManagementPort(int mainPort) { - return mainPort + (DEFAULT_MANAGEMENT_PORT - DEFAULT_PORT); + return mainPort + (DEFAULT_MANAGEMENT_PORT - (_broker.equals(VM) ? DEFAULT_VM_PORT : DEFAULT_PORT)); } /** @@ -484,7 +484,16 @@ public class QpidTestCase extends TestCase setConfigurationProperty("management.jmxport", String.valueOf(getManagementPort(port))); saveTestConfiguration(); // create an in_VM broker - ApplicationRegistry.initialise(new ConfigurationFileApplicationRegistry(_configFile), port); + final ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(_configFile); + try + { + ApplicationRegistry.initialise(registry, port); + } + catch (Exception e) + { + registry.close(); + throw e; + } TransportConnection.createVMBroker(port); } else if (!_broker.equals(EXTERNAL)) @@ -511,12 +520,12 @@ public class QpidTestCase extends TestCase // Use the environment variable to set amqj.logging.level for the broker // The value used is a 'server' value in the test configuration to - // allow a differentiation between the client and broker logging levels. + // allow a differentiation between the client and broker logging levels. if (System.getProperty("amqj.server.logging.level") != null) { setBrokerEnvironment("AMQJ_LOGGING_LEVEL", System.getProperty("amqj.server.logging.level")); } - + // Add all the environment settings the test requested if (!_env.isEmpty()) { @@ -766,7 +775,7 @@ public class QpidTestCase extends TestCase _propertiesSetForBroker.put(property, value); } - } + } /** * Set a System (-D) property for this test run. @@ -790,7 +799,7 @@ public class QpidTestCase extends TestCase * Java Broker via a -D value defined in QPID_OPTS. * * If the value should not be set on the broker then use - * setTestClientSystemProperty(). + * setTestClientSystemProperty(). * * @param property the property to set * @param value the new value to use @@ -800,7 +809,7 @@ public class QpidTestCase extends TestCase // Record the value for the external broker _propertiesSetForBroker.put(property, value); - //Set the value for the test client vm aswell. + //Set the value for the test client vm aswell. setTestClientSystemProperty(property, value); } @@ -816,7 +825,7 @@ public class QpidTestCase extends TestCase { // Record the current value so we can revert it later. _propertiesSetForTestOnly.put(property, System.getProperty(property)); - } + } System.setProperty(property, value); } @@ -1153,7 +1162,7 @@ public class QpidTestCase extends TestCase int count, int batchSize) throws Exception { return sendMessage(session, destination, count, 0, batchSize); - } + } /** * Send messages to the given destination. @@ -1199,7 +1208,7 @@ public class QpidTestCase extends TestCase // Ensure we commit the last messages // Commit the session if we are transacted and // we have no batchSize or - // our count is not divible by batchSize. + // our count is not divible by batchSize. if (session.getTransacted() && ( batchSize == 0 || count % batchSize != 0)) { @@ -1249,13 +1258,13 @@ public class QpidTestCase extends TestCase { reloadBroker(0); } - + public void reloadBroker(int port) throws ConfigurationException, IOException { if (_broker.equals(VM)) { ApplicationRegistry.getInstance().getConfiguration().reparseConfigFileSecuritySections(); - } + } else // FIXME: should really use the JMX interface to do this { /* @@ -1266,11 +1275,11 @@ public class QpidTestCase extends TestCase BufferedReader reader = new BufferedReader (new InputStreamReader(p.getInputStream())); String cmd = "/bin/kill -SIGHUP " + reader.readLine(); p = Runtime.getRuntime().exec(cmd); - + LogMonitor _monitor = new LogMonitor(_outputFile); assertTrue("The expected server security configuration reload did not occur", _monitor.waitForMessage(ServerConfiguration.SECURITY_CONFIG_RELOADED, LOGMONITOR_TIMEOUT)); - + } } } diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index cb72da2a88..ac2d7bb823 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -34,6 +34,9 @@ org.apache.qpid.test.unit.xa.FaultTest#testForget // the 0-10 c++ broker does not implement priority / this test depends on a Java broker extension for queue creation org.apache.qpid.server.queue.PriorityTest +// the 0-10 c++ broker does not implement the extended LVQ semantics which the Java Broker does +org.apache.qpid.server.queue.ConflationQueueTest + //this test checks explicitly for 0-8 flow control semantics org.apache.qpid.test.client.FlowControlTest |