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 }