001 /*
002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003 * Copyright (C) 2011 NightLabs Consulting GmbH
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
017 */
018 package org.cumulus4j.store.crypto.keymanager.messagebroker;
019
020 import org.cumulus4j.keymanager.back.shared.Message;
021 import org.cumulus4j.store.crypto.keymanager.messagebroker.inmemory.MessageBrokerInMemory;
022 import org.cumulus4j.store.crypto.keymanager.messagebroker.pmf.MessageBrokerPMF;
023 import org.slf4j.Logger;
024 import org.slf4j.LoggerFactory;
025
026 /**
027 * JVM-singleton to access the {@link #getActiveMessageBroker() active message-broker}.
028 * It handles the registration and instantiation of {@link MessageBroker} implementations.
029 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
030 */
031 public class MessageBrokerRegistry
032 {
033 private static Logger logger = LoggerFactory.getLogger(MessageBrokerRegistry.class);
034
035 private static MessageBrokerRegistry sharedInstance = new MessageBrokerRegistry();
036
037 public static MessageBrokerRegistry sharedInstance() { return sharedInstance; }
038
039 /**
040 * The system property configuring which message-broker-implementation is to be used.
041 * If it is not specified, a list of known implementations is tried out and the first one which
042 * could be instantiated successfully is used.
043 */
044 public static final String SYSTEM_PROPERTY_ACTIVE_MESSAGE_BROKER = "cumulus4j.MessageBrokerRegistry.activeMessageBroker";
045
046 private static final Class<?>[] MESSAGE_BROKER_IMPLEMENTATION_CLASSES = {
047 MessageBrokerPMF.class,
048 MessageBrokerInMemory.class
049 };
050
051 private volatile MessageBroker activeMessageBroker;
052
053 /**
054 * Get the active {@link MessageBroker}. All {@link Message}s are transmitted over this active instance.
055 * If there is no active <code>MessageBroker</code>, yet, this method will
056 * check the system property {@value #SYSTEM_PROPERTY_ACTIVE_MESSAGE_BROKER} and either instantiate the
057 * class configured there or iterate a list of known <code>MessageBroker</code>-implementation-classes.
058 * @return the active <code>MessageBroker</code>; never <code>null</code>. If no active message-broker is set
059 * and none can be instantiated, an exception is thrown.
060 */
061 public MessageBroker getActiveMessageBroker()
062 {
063 MessageBroker result = activeMessageBroker;
064 if (result == null) {
065 synchronized (this) { // correct & fast double-checked-locking with both 'volatile' and local variable 'result'.
066 result = activeMessageBroker;
067 if (result == null) {
068 String messageBrokerImplClassName = System.getProperty(SYSTEM_PROPERTY_ACTIVE_MESSAGE_BROKER);
069 if (messageBrokerImplClassName == null || messageBrokerImplClassName.trim().isEmpty()) {
070 logger.info("getActiveMessageBroker: System property '{}' was not specified. Auto-detecting appropriate MessageBroker-implementation.", SYSTEM_PROPERTY_ACTIVE_MESSAGE_BROKER);
071
072 for (Class<?> c : MESSAGE_BROKER_IMPLEMENTATION_CLASSES) {
073 try {
074 MessageBroker mb = (MessageBroker) c.newInstance();
075 result = mb;
076 break;
077 } catch (Exception e) {
078 logger.warn("getActiveMessageBroker: Could not instantiate " + c.getName() + ": " + e, e);
079 }
080 }
081
082 if (result == null)
083 throw new IllegalStateException("None of the available MessageBroker implementations could be successfully instantiated!");
084 }
085 else {
086 try {
087 Class<?> messageBrokerImplClass = Class.forName(messageBrokerImplClassName);
088 result = (MessageBroker) messageBrokerImplClass.newInstance();
089 } catch (ClassNotFoundException e) {
090 throw new RuntimeException(e);
091 } catch (InstantiationException e) {
092 throw new RuntimeException(e);
093 } catch (IllegalAccessException e) {
094 throw new RuntimeException(e);
095 }
096 }
097
098 activeMessageBroker = result;
099 logger.info("getActiveMessageBroker: New activeMessageBroker={}", result);
100 }
101 }
102 }
103
104 return result;
105 }
106
107 /**
108 * Set the active {@link MessageBroker}. Whatever is passed here will be returned by {@link #getActiveMessageBroker()}
109 * except for <code>null</code>. Setting <code>null</code> will cause {@link #getActiveMessageBroker()} to perform
110 * a re-initialisation (i.e. instantiate a <code>MessageBroker</code> as needed).
111 * @param messageBroker the {@link MessageBroker} instance to be set or <code>null</code> to clear the current one.
112 */
113 public void setActiveMessageBroker(MessageBroker messageBroker)
114 {
115 MessageBroker amb = this.activeMessageBroker;
116 if (amb != null && amb != messageBroker) {
117 Exception x = new IllegalStateException("An active MessageBroker already exists! Changing the active MessageBroker now is highly discouraged as it may cause errors!");
118 logger.warn("setActiveMessageBroker: " + x, x);
119 }
120
121 this.activeMessageBroker = messageBroker;
122 logger.info("setActiveMessageBroker: New activeMessageBroker={}", messageBroker);
123 }
124 }