001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.plugin.java; 018 019import java.util.Arrays; 020import java.util.List; 021import java.util.Set; 022 023import org.apache.activemq.broker.Broker; 024import org.apache.activemq.broker.region.policy.PolicyEntry; 025import org.apache.activemq.broker.region.policy.PolicyMap; 026import org.apache.activemq.broker.region.virtual.VirtualDestination; 027import org.apache.activemq.command.ActiveMQDestination; 028import org.apache.activemq.network.DiscoveryNetworkConnector; 029import org.apache.activemq.plugin.AbstractRuntimeConfigurationBroker; 030import org.apache.activemq.plugin.UpdateVirtualDestinationsTask; 031import org.apache.activemq.plugin.util.PolicyEntryUtil; 032import org.apache.activemq.security.AuthorizationBroker; 033import org.apache.activemq.security.AuthorizationMap; 034import org.apache.activemq.security.SimpleAuthenticationBroker; 035import org.apache.activemq.security.SimpleAuthenticationPlugin; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039public class JavaRuntimeConfigurationBroker extends AbstractRuntimeConfigurationBroker { 040 041 /** 042 * @param next 043 */ 044 public JavaRuntimeConfigurationBroker(Broker next) { 045 super(next); 046 } 047 048 public static final Logger LOG = LoggerFactory.getLogger(JavaRuntimeConfigurationBroker.class); 049 050 051 //Virtual Destinations 052 public void setVirtualDestinations(final VirtualDestination[] virtualDestinations) { 053 this.addDestinationWork.add(new UpdateVirtualDestinationsTask(this) { 054 @Override 055 protected VirtualDestination[] getVirtualDestinations() { 056 return virtualDestinations; 057 } 058 }); 059 } 060 061 /** 062 * Set the virtual destinations and apply immediately, instead of waiting for a new 063 * destination or connection to trigger the work. 064 * 065 * @param virtualDestinations 066 * @param applyImmediately 067 * @throws Exception 068 */ 069 public void setVirtualDestinations(final VirtualDestination[] virtualDestinations, boolean applyImmediately) throws Exception { 070 setVirtualDestinations(virtualDestinations); 071 if (applyImmediately) { 072 this.applyDestinationWork(); 073 } 074 } 075 076 //New Destinations 077 public void setDestinations(final ActiveMQDestination[] destinations) { 078 for (ActiveMQDestination destination : destinations) { 079 try { 080 if (!containsDestination(destination)) { 081 this.addDestination(this.getBrokerService().getAdminConnectionContext(), destination, true); 082 this.info("Added destination " + destination); 083 } 084 } catch (Exception e) { 085 this.info("Failed to add a new destination for: " + destination, e); 086 } 087 } 088 } 089 090 protected boolean containsDestination(ActiveMQDestination destination) throws Exception { 091 return Arrays.asList(this.getBrokerService().getRegionBroker().getDestinations()).contains(destination); 092 } 093 094 public void addNewDestination(ActiveMQDestination destination) { 095 try { 096 this.addDestination(this.getBrokerService().getAdminConnectionContext(), destination, true); 097 this.info("Added destination " + destination); 098 } catch (Exception e) { 099 this.info("Failed to add a new destination for: " + destination, e); 100 } 101 } 102 103 //Network Connectors 104 public void addNetworkConnector(final DiscoveryNetworkConnector nc) { 105 try { 106 if (!getBrokerService().getNetworkConnectors().contains(nc)) { 107 getBrokerService().addNetworkConnector(nc); 108 nc.start(); 109 info("started new network connector: " + nc); 110 } else { 111 info("skipping network connector add, already exists: " + nc); 112 } 113 } catch (Exception e) { 114 info("Failed to add new networkConnector " + nc, e); 115 } 116 } 117 118 public void updateNetworkConnector(final DiscoveryNetworkConnector nc) { 119 removeNetworkConnector(nc); 120 addNetworkConnector(nc); 121 } 122 123 public void removeNetworkConnector(final DiscoveryNetworkConnector existingCandidate) { 124 if (getBrokerService().removeNetworkConnector(existingCandidate)) { 125 try { 126 existingCandidate.stop(); 127 info("stopped and removed networkConnector: " + existingCandidate); 128 } catch (Exception e) { 129 info("Failed to stop removed network connector: " + existingCandidate); 130 } 131 } 132 } 133 134 //Policy entries 135 public void addNewPolicyEntry(PolicyEntry addition) { 136 PolicyMap existingMap = getBrokerService().getDestinationPolicy(); 137 existingMap.put(addition.getDestination(), addition); 138 PolicyEntryUtil.applyRetrospectively(this, addition, null); 139 info("added policy for: " + addition.getDestination()); 140 } 141 142 143 /** 144 * This method will modify an existing policy entry that matches the destination 145 * set on the PolicyEntry passed in. 146 * 147 * The PolicyEntry reference must already be in the PolicyMap or it won't be updated. 148 * To modify the entry the best way is to look up the existing PolicyEntry from the 149 * PolicyMap, make changes to it, and pass it to this method to apply. 150 * 151 * To create or replace an existing entry (if the destination matches), see 152 * {@link #modifyPolicyEntry(PolicyEntry, boolean) 153 * 154 * 155 * @param existing 156 */ 157 public void modifyPolicyEntry(PolicyEntry existing) { 158 modifyPolicyEntry(existing, false); 159 } 160 161 public void modifyPolicyEntry(PolicyEntry existing, boolean createOrReplace) { 162 modifyPolicyEntry(existing, createOrReplace, null); 163 } 164 165 /** 166 * This method will modify an existing policy entry that matches the destination 167 * set on the PolicyEntry passed in. If createOrReplace is true, a new policy 168 * will be created if it doesn't exist and a policy will be replaced in the PolicyMap, 169 * versus modified, if it is a different reference but the destinations for the Policy match. 170 * 171 * If createOrReplace is false, the policy update will only be applied if 172 * the PolicyEntry reference already exists in the PolicyMap. 173 * 174 * includedProperties is a list of properties that will be applied retrospectively. If 175 * the list is null, then all properties on the policy will be reapplied to the destination. 176 * This allows the ability to limit which properties are applied to existing destinations. 177 * 178 * @param existing 179 * @param createIfAbsent 180 * @param includedProperties - optional list of properties to apply retrospectively 181 */ 182 public void modifyPolicyEntry(PolicyEntry existing, boolean createOrReplace, 183 Set<String> includedProperties) { 184 PolicyMap existingMap = this.getBrokerService().getDestinationPolicy(); 185 186 //First just look up by the destination type to see if anything matches 187 PolicyEntry existingEntry = PolicyEntryUtil.findEntryByDestination(this, existing); 188 189 //handle createOrReplace 190 if (createOrReplace) { 191 //if not found at all, go ahead and insert the policy entry 192 if (existingEntry == null) { 193 existingMap.put(existing.getDestination(), existing); 194 existingEntry = existing; 195 //If found but the objects are different, remove the old policy entry 196 //and replace it with the new one 197 } else if (!existing.equals(existingEntry)) { 198 synchronized(existingMap) { 199 existingMap.remove(existingEntry.getDestination(), existingEntry); 200 existingMap.put(existing.getDestination(), existing); 201 } 202 existingEntry = existing; 203 } 204 } 205 206 //Make sure that at this point the passed in object and the entry in 207 //the map are the same 208 if (existingEntry != null && existingEntry.equals(existing)) { 209 PolicyEntryUtil.applyRetrospectively(this, existingEntry, includedProperties); 210 this.info("updated policy for: " + existingEntry.getDestination()); 211 } else { 212 throw new IllegalArgumentException("The policy can not be updated because it either does not exist or the PolicyEntry" 213 + " reference does not match an existing PolicyEntry in the PolicyMap. To replace an" 214 + " entry (versus modifying) or add, set createOrReplace to true. " 215 + existing + ", destination:" + existing.getDestination()); 216 } 217 } 218 219 //authentication plugin 220 public void updateSimpleAuthenticationPlugin(final SimpleAuthenticationPlugin updatedPlugin) { 221 try { 222 final SimpleAuthenticationBroker authenticationBroker = 223 (SimpleAuthenticationBroker) getBrokerService().getBroker().getAdaptor(SimpleAuthenticationBroker.class); 224 addConnectionWork.add(new Runnable() { 225 @Override 226 public void run() { 227 authenticationBroker.setUserGroups(updatedPlugin.getUserGroups()); 228 authenticationBroker.setUserPasswords(updatedPlugin.getUserPasswords()); 229 authenticationBroker.setAnonymousAccessAllowed(updatedPlugin.isAnonymousAccessAllowed()); 230 authenticationBroker.setAnonymousUser(updatedPlugin.getAnonymousUser()); 231 authenticationBroker.setAnonymousGroup(updatedPlugin.getAnonymousGroup()); 232 } 233 }); 234 } catch (Exception e) { 235 info("failed to apply SimpleAuthenticationPlugin modifications to SimpleAuthenticationBroker", e); 236 } 237 } 238 239 //authorization map 240 public void updateAuthorizationMap(final AuthorizationMap authorizationMap) { 241 try { 242 // replace authorization map - need exclusive write lock to total broker 243 AuthorizationBroker authorizationBroker = 244 (AuthorizationBroker) getBrokerService().getBroker().getAdaptor(AuthorizationBroker.class); 245 246 authorizationBroker.setAuthorizationMap(authorizationMap); 247 } catch (Exception e) { 248 info("failed to apply modified AuthorizationMap to AuthorizationBroker", e); 249 } 250 } 251}