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