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