View Javadoc
1   /*
2    * Copyright 2001-2008 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  package org.apache.juddi.config;
18  
19  import java.io.File;
20  import java.net.MalformedURLException;
21  import java.net.URL;
22  import java.util.List;
23  import java.util.Properties;
24  
25  import javax.persistence.EntityManager;
26  import javax.persistence.EntityTransaction;
27  
28  import org.apache.commons.configuration.CompositeConfiguration;
29  import org.apache.commons.configuration.Configuration;
30  import org.apache.commons.configuration.ConfigurationException;
31  import org.apache.commons.configuration.MapConfiguration;
32  import org.apache.commons.configuration.SystemConfiguration;
33  import org.apache.commons.configuration.XMLConfiguration;
34  import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.juddi.ClassUtil;
38  import org.apache.juddi.Registry;
39  import org.apache.juddi.keygen.KeyGenerator;
40  import org.apache.juddi.model.UddiEntityPublisher;
41  
42  /**
43   * Handles the application level configuration for jUDDI. By default it first
44   * looks at system properties (juddi.propertiesFile)
45   * @author <a href="mailto:kstam@apache.org">Kurt T Stam</a>
46   * @author <a href="mailto:jfaath@apache.org">Jeff Faath</a>
47   */
48  public class AppConfig 
49  {
50          /**
51           * This system property's value should be a path to a configuration file
52           */
53          public static final String JUDDI_CONFIGURATION_FILE_SYSTEM_PROPERTY="juddi.propertiesFile";
54          /**
55           * The default configuration file name for juddi
56           */
57  	public static final String JUDDI_PROPERTIES = "juddiv3.xml";
58  	private Log log = LogFactory.getLog(AppConfig.class);
59  	private Configuration config;
60  	private static AppConfig instance=null;
61          private static URL loadedFrom=null;
62          private static XMLConfiguration propConfig=null;
63          
64          /**
65           * Enables an administrator to identify the physical location of the configuration file from which it was loaded.<br>
66           * Always call via the singleton function AppConfig.getInstance().getConfigFileURL()
67           * @since 3.2
68           * @return may return null if no config file was found
69           */
70          public static  URL getConfigFileURL()
71          {
72              return loadedFrom;
73          }
74  	
75  	/**
76  	 * Constructor (note Singleton pattern).
77  	 * @throws ConfigurationException
78  	 */
79  	private AppConfig() throws ConfigurationException 
80  	{
81  		loadConfiguration();
82  	}
83          public static void setJuddiProperty(String key, Object val) throws ConfigurationException{
84                  if (instance==null) {
85  			instance = new AppConfig();
86  		}
87                  propConfig.setProperty(key, val);
88                  propConfig.save();
89          }
90          
91          public static void saveConfiguration() throws ConfigurationException{
92                  getConfiguration(); //findbugs will flag this as useless, but its not
93                  propConfig.save();
94          }
95         
96          
97  	/**
98  	 * Does the actual work of reading the configuration from System
99  	 * Properties and/or juddiv3.xml file. When the juddiv3.xml
100 	 * file is updated the file will be reloaded. By default the reloadDelay is
101 	 * set to 1 second to prevent excessive date stamp checking.
102 	 */
103 	private void loadConfiguration() throws ConfigurationException
104 	{
105 		//Properties from system properties
106 		CompositeConfiguration compositeConfig = new CompositeConfiguration();
107 		compositeConfig.addConfiguration(new SystemConfiguration());
108 		//Properties from file
109                 //changed 7-19-2013 AO for JUDDI-627
110 		propConfig = null;
111 	        final String filename = System.getProperty(JUDDI_CONFIGURATION_FILE_SYSTEM_PROPERTY);
112 		if (filename != null) {
113                   propConfig = new XMLConfiguration (filename); 
114                     try {
115                         loadedFrom = new File(filename).toURI().toURL();
116                     //	propConfig = new PropertiesConfiguration(filename);
117                     } catch (MalformedURLException ex) {
118                       try {
119                           loadedFrom = new URL("file://" + filename);
120                       } catch (MalformedURLException ex1) {
121                           log.warn("unable to get an absolute path to " + filename + ". This may be ignorable if everything works properly.", ex1);
122                       }
123                     }
124 		} else {
125 			//propConfig = new PropertiesConfiguration(JUDDI_PROPERTIES);
126                     propConfig = new XMLConfiguration(JUDDI_PROPERTIES);
127                     loadedFrom = ClassUtil.getResource(JUDDI_PROPERTIES, this.getClass()); 
128 		}
129                 //Hey! this may break things
130                 propConfig.setAutoSave(true);
131 
132 		log.info("Reading from jUDDI config file from:  " + loadedFrom);
133 		long refreshDelay = propConfig.getLong(Property.JUDDI_CONFIGURATION_RELOAD_DELAY, 1000l);
134 		log.debug("Setting refreshDelay to " + refreshDelay);
135 		FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
136 		fileChangedReloadingStrategy.setRefreshDelay(refreshDelay);
137 		propConfig.setReloadingStrategy(fileChangedReloadingStrategy);
138 		compositeConfig.addConfiguration(propConfig);
139 		
140 		
141 		Properties properties = new Properties();
142 		if ("Hibernate".equals(propConfig.getString(Property.PERSISTENCE_PROVIDER))) {
143 			if (propConfig.containsKey(Property.DATASOURCE)) 
144 				properties.put("hibernate.connection.datasource",propConfig.getString(Property.DATASOURCE));
145 			if (propConfig.containsKey(Property.HBM_DDL_AUTO))
146 				properties.put("hibernate.hbm2ddl.auto",propConfig.getString(Property.HBM_DDL_AUTO));
147 			if (propConfig.containsKey(Property.DEFAULT_SCHEMA))
148 				properties.put("hibernate.default_schema",propConfig.getString(Property.DEFAULT_SCHEMA));
149 			if (propConfig.containsKey(Property.HIBERNATE_DIALECT))
150 				properties.put("hibernate.dialect",propConfig.getString(Property.HIBERNATE_DIALECT));
151 		}
152 		// initialize the entityManagerFactory.
153 		PersistenceManager.initializeEntityManagerFactory(propConfig.getString(Property.JUDDI_PERSISTENCEUNIT_NAME), properties);
154 		// Properties from the persistence layer 
155 		MapConfiguration persistentConfig = new MapConfiguration(getPersistentConfiguration(compositeConfig));
156 		
157 		compositeConfig.addConfiguration(persistentConfig);
158 		//Making the new configuration globally accessible.
159 		config = compositeConfig;
160 	}
161 
162 	/*
163 	 * This method will build any "persisted" properties. Persisted properties are those that are stored in the database.  These values
164 	 * should be stored when the application is installed.  If they don't exist, then an error should occur.
165 	 */
166 	private Properties getPersistentConfiguration(Configuration config) throws ConfigurationException {
167 		Properties result = new Properties();
168 		
169 		EntityManager em = PersistenceManager.getEntityManager();
170 		EntityTransaction tx = em.getTransaction();
171 		try {
172 			boolean seedAlways = config.getBoolean("juddi.seed.always",false);
173 			if (seedAlways || !Install.alreadyInstalled(config)) {
174 			    if (seedAlways) {
175 			    	log.info("Installing UDDI seed data, loading...");
176 			    } else {
177 			    	log.info("The 'root' publisher was not found, loading...");
178 			    }
179 				try {
180 					Install.install(config);
181 				} catch (Exception e) {
182 					throw new ConfigurationException(e);
183 				} catch (Throwable t) {
184 					throw new ConfigurationException(t);
185 				}
186 			}
187 
188 			tx.begin();
189 	
190 			String rootPublisherStr = config.getString(Property.JUDDI_ROOT_PUBLISHER);
191 			UddiEntityPublisher  rootPublisher = new UddiEntityPublisher(rootPublisherStr);
192 			rootPublisher.populateKeyGeneratorKeys(em);
193 			List<String> rootKeyGenList = rootPublisher.getKeyGeneratorKeys();
194 			if (rootKeyGenList == null || rootKeyGenList.size() == 0)
195 				throw new ConfigurationException("The 'root' publisher key generator was not found.  Please make sure that the application is properly installed.");
196 			
197 			String rootKeyGen = rootKeyGenList.iterator().next();
198 			//rootKeyGen = rootKeyGen.substring((KeyGenerator.UDDI_SCHEME + KeyGenerator.PARTITION_SEPARATOR).length());
199 			rootKeyGen = rootKeyGen.substring(0, rootKeyGen.length() - (KeyGenerator.PARTITION_SEPARATOR + KeyGenerator.KEYGENERATOR_SUFFIX).length());
200 			log.debug("root partition:  " + rootKeyGen);
201 	
202 			result.setProperty(Property.JUDDI_ROOT_PARTITION, rootKeyGen);
203 			
204 			// The node Id is defined as the business key of the business entity categorized as a node.  This entity is saved as part of the install.
205 			// Only one business entity should be categorized as a node.
206 			String nodeId = config.getString(Property.JUDDI_NODE_ID);
207                         if (nodeId==null)
208                                 log.fatal("Error! " + Property.JUDDI_NODE_ID + " is not defined in the config!");
209                         else
210                                 result.setProperty(Property.JUDDI_NODE_ID, nodeId);
211 			/*
212                         CategoryBag categoryBag = new CategoryBag();
213 			KeyedReference keyedRef = new KeyedReference();
214 			keyedRef.setTModelKey(Constants.NODE_CATEGORY_TMODEL);
215 			keyedRef.setKeyValue(Constants.NODE_KEYVALUE);
216 			categoryBag.getKeyedReference().add(keyedRef);
217 			List<?> keyList = FindBusinessByCategoryQuery.select(em, new FindQualifiers(), categoryBag, null);
218 			if (keyList != null && keyList.size() > 1)
219                         {
220                                 StringBuilder sb = new StringBuilder();
221                                 Iterator<?> iterator = keyList.iterator();
222                                 while(iterator.hasNext()){
223                                         sb.append(iterator.next()).append(",");
224                                 }
225 				//
226                                 //throw new ConfigurationException("Only one business entity can be categorized as the node. Config loaded from " + loadedFrom + " Key's listed at the node: " + sb.toString());
227                                 //unless of course, we are in a replicated environment
228                         }
229 			if (keyList != null && keyList.size() > 0) {
230 				nodeId = (String)keyList.get(0);
231 			}
232 			else
233 				throw new ConfigurationException("A node business entity was not found.  Please make sure that the application is properly installed.");
234 			*/
235                         String rootbiz=config.getString(Property.JUDDI_NODE_ROOT_BUSINESS);
236                         if (rootbiz==null)
237                                 log.fatal("Error! " + Property.JUDDI_NODE_ROOT_BUSINESS + " is not defined in the config");
238                         else
239                                 result.setProperty(Property.JUDDI_NODE_ROOT_BUSINESS, rootbiz);
240                         
241                         
242 			
243 			tx.commit();
244 			return result;
245 		} finally {
246 			if (tx.isActive()) {
247 				tx.rollback();
248 			}
249 			em.close();
250 		}
251 	}
252 	
253 	
254 	/**
255 	 * Obtains the reference to the Singleton instance.
256 	 * 
257 	 * @return the APplicationConfuration Singleton Instance.
258 	 * @throws ConfigurationException
259 	 */
260 	public static AppConfig getInstance() throws ConfigurationException 
261 	{
262 		if (instance==null) {
263 			instance = new AppConfig();
264 		}
265 		return instance;
266 	}
267 	/**
268 	 * Hook to receive configuration reload events from an external application.
269 	 * 
270 	 * @throws ConfigurationException
271 	 */
272 	public static void reloadConfig() throws ConfigurationException
273 	{
274 		Registry.stop();
275 		getInstance().loadConfiguration();
276 		Registry.start();
277 	}
278         
279         public static void triggerReload() throws ConfigurationException{
280                 getInstance().loadConfiguration();
281         }
282 	/**
283 	 * The object from which property values can be obtained.
284 	 * @return the commons Configuration interface
285 	 * @throws ConfigurationException 
286 	 */
287 	public static Configuration getConfiguration() throws ConfigurationException
288 	{
289 		return getInstance().config;
290 	}
291 }