/**
* 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.activemq.plugin.java;
import java.util.Arrays;
import java.util.Set;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.region.policy.PolicyEntry;
import org.apache.activemq.broker.region.policy.PolicyMap;
import org.apache.activemq.broker.region.virtual.VirtualDestination;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.network.DiscoveryNetworkConnector;
import org.apache.activemq.plugin.AbstractRuntimeConfigurationBroker;
import org.apache.activemq.plugin.UpdateVirtualDestinationsTask;
import org.apache.activemq.plugin.util.PolicyEntryUtil;
import org.apache.activemq.security.AuthorizationBroker;
import org.apache.activemq.security.AuthorizationMap;
import org.apache.activemq.security.SimpleAuthenticationBroker;
import org.apache.activemq.security.SimpleAuthenticationPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JavaRuntimeConfigurationBroker extends AbstractRuntimeConfigurationBroker {
/**
* @param next
*/
public JavaRuntimeConfigurationBroker(Broker next) {
super(next);
}
public static final Logger LOG = LoggerFactory.getLogger(JavaRuntimeConfigurationBroker.class);
//Virtual Destinations
public void setVirtualDestinations(final VirtualDestination[] virtualDestinations) {
this.addDestinationWork.add(new UpdateVirtualDestinationsTask(this) {
@Override
protected VirtualDestination[] getVirtualDestinations() {
return virtualDestinations;
}
});
}
/**
* Set the virtual destinations and apply immediately, instead of waiting for a new
* destination or connection to trigger the work.
*
* @param virtualDestinations
* @param applyImmediately
* @throws Exception
*/
public void setVirtualDestinations(final VirtualDestination[] virtualDestinations, boolean applyImmediately) throws Exception {
setVirtualDestinations(virtualDestinations);
if (applyImmediately) {
this.applyDestinationWork();
}
}
//New Destinations
public void setDestinations(final ActiveMQDestination[] destinations) {
for (ActiveMQDestination destination : destinations) {
try {
if (!containsDestination(destination)) {
this.addDestination(this.getBrokerService().getAdminConnectionContext(), destination, true);
this.info("Added destination " + destination);
}
} catch (Exception e) {
this.info("Failed to add a new destination for: " + destination, e);
}
}
}
protected boolean containsDestination(ActiveMQDestination destination) throws Exception {
return Arrays.asList(this.getBrokerService().getRegionBroker().getDestinations()).contains(destination);
}
public void addNewDestination(ActiveMQDestination destination) {
try {
this.addDestination(this.getBrokerService().getAdminConnectionContext(), destination, true);
this.info("Added destination " + destination);
} catch (Exception e) {
this.info("Failed to add a new destination for: " + destination, e);
}
}
//Network Connectors
public void addNetworkConnector(final DiscoveryNetworkConnector nc) {
try {
if (!getBrokerService().getNetworkConnectors().contains(nc)) {
getBrokerService().addNetworkConnector(nc);
getBrokerService().startNetworkConnector(nc, null);
info("started new network connector: " + nc);
} else {
info("skipping network connector add, already exists: " + nc);
}
} catch (Exception e) {
info("Failed to add new networkConnector " + nc, e);
}
}
public void updateNetworkConnector(final DiscoveryNetworkConnector nc) {
removeNetworkConnector(nc);
addNetworkConnector(nc);
}
public void removeNetworkConnector(final DiscoveryNetworkConnector existingCandidate) {
if (getBrokerService().removeNetworkConnector(existingCandidate)) {
try {
existingCandidate.stop();
info("stopped and removed networkConnector: " + existingCandidate);
} catch (Exception e) {
info("Failed to stop removed network connector: " + existingCandidate);
}
}
}
//Policy entries
public void addNewPolicyEntry(PolicyEntry addition) {
PolicyMap existingMap = getBrokerService().getDestinationPolicy();
existingMap.put(addition.getDestination(), addition);
PolicyEntryUtil.applyRetrospectively(this, addition, null);
info("added policy for: " + addition.getDestination());
}
/**
* This method will modify an existing policy entry that matches the destination
* set on the PolicyEntry passed in.
*
* The PolicyEntry reference must already be in the PolicyMap or it won't be updated.
* To modify the entry the best way is to look up the existing PolicyEntry from the
* PolicyMap, make changes to it, and pass it to this method to apply.
*
* To create or replace an existing entry (if the destination matches), see
* {@link #modifyPolicyEntry(PolicyEntry, boolean)
*
*
* @param existing
*/
public void modifyPolicyEntry(PolicyEntry existing) {
modifyPolicyEntry(existing, false);
}
public void modifyPolicyEntry(PolicyEntry existing, boolean createOrReplace) {
modifyPolicyEntry(existing, createOrReplace, null);
}
/**
* This method will modify an existing policy entry that matches the destination
* set on the PolicyEntry passed in. If createOrReplace is true, a new policy
* will be created if it doesn't exist and a policy will be replaced in the PolicyMap,
* versus modified, if it is a different reference but the destinations for the Policy match.
*
* If createOrReplace is false, the policy update will only be applied if
* the PolicyEntry reference already exists in the PolicyMap.
*
* includedProperties is a list of properties that will be applied retrospectively. If
* the list is null, then all properties on the policy will be reapplied to the destination.
* This allows the ability to limit which properties are applied to existing destinations.
*
* @param existing
* @param createIfAbsent
* @param includedProperties - optional list of properties to apply retrospectively
*/
public void modifyPolicyEntry(PolicyEntry existing, boolean createOrReplace,
Set<String> includedProperties) {
PolicyMap existingMap = this.getBrokerService().getDestinationPolicy();
//First just look up by the destination type to see if anything matches
PolicyEntry existingEntry = PolicyEntryUtil.findEntryByDestination(this, existing);
//handle createOrReplace
if (createOrReplace) {
//if not found at all, go ahead and insert the policy entry
if (existingEntry == null) {
existingMap.put(existing.getDestination(), existing);
existingEntry = existing;
//If found but the objects are different, remove the old policy entry
//and replace it with the new one
} else if (!existing.equals(existingEntry)) {
synchronized(existingMap) {
existingMap.remove(existingEntry.getDestination(), existingEntry);
existingMap.put(existing.getDestination(), existing);
}
existingEntry = existing;
}
}
//Make sure that at this point the passed in object and the entry in
//the map are the same
if (existingEntry != null && existingEntry.equals(existing)) {
PolicyEntryUtil.applyRetrospectively(this, existingEntry, includedProperties);
this.info("updated policy for: " + existingEntry.getDestination());
} else {
throw new IllegalArgumentException("The policy can not be updated because it either does not exist or the PolicyEntry"
+ " reference does not match an existing PolicyEntry in the PolicyMap. To replace an"
+ " entry (versus modifying) or add, set createOrReplace to true. "
+ existing + ", destination:" + existing.getDestination());
}
}
//authentication plugin
public void updateSimpleAuthenticationPlugin(final SimpleAuthenticationPlugin updatedPlugin) {
try {
final SimpleAuthenticationBroker authenticationBroker =
(SimpleAuthenticationBroker) getBrokerService().getBroker().getAdaptor(SimpleAuthenticationBroker.class);
addConnectionWork.add(new Runnable() {
@Override
public void run() {
authenticationBroker.setUserGroups(updatedPlugin.getUserGroups());
authenticationBroker.setUserPasswords(updatedPlugin.getUserPasswords());
authenticationBroker.setAnonymousAccessAllowed(updatedPlugin.isAnonymousAccessAllowed());
authenticationBroker.setAnonymousUser(updatedPlugin.getAnonymousUser());
authenticationBroker.setAnonymousGroup(updatedPlugin.getAnonymousGroup());
}
});
} catch (Exception e) {
info("failed to apply SimpleAuthenticationPlugin modifications to SimpleAuthenticationBroker", e);
}
}
//authorization map
public void updateAuthorizationMap(final AuthorizationMap authorizationMap) {
try {
// replace authorization map - need exclusive write lock to total broker
AuthorizationBroker authorizationBroker =
(AuthorizationBroker) getBrokerService().getBroker().getAdaptor(AuthorizationBroker.class);
authorizationBroker.setAuthorizationMap(authorizationMap);
} catch (Exception e) {
info("failed to apply modified AuthorizationMap to AuthorizationBroker", e);
}
}
}