001/* 002 * Copyright 2012 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.servlet; 017 018import java.io.File; 019import java.text.ParseException; 020import java.text.SimpleDateFormat; 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Date; 024import java.util.HashMap; 025import java.util.Map; 026 027import org.apache.avalon.framework.configuration.Configuration; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031import org.ametys.runtime.util.AmetysHomeHelper; 032 033/** 034 * Java representation of the WEB-INF/param/runtime.xml file.<br> 035 * Contains all runtime configuration values. 036 */ 037public final class RuntimeConfig 038{ 039 // shared instance 040 private static RuntimeConfig __config; 041 042 private boolean _safeMode; 043 044 private String _defaultWorkspace; 045 private String _initClass; 046 private final Collection<String> _pluginsLocations = new ArrayList<>(); 047 private final Collection<String> _excludedPlugins = new ArrayList<>(); 048 private final Collection<String> _excludedFeatures = new ArrayList<>(); 049 private final Collection<String> _excludedWorkspaces = new ArrayList<>(); 050 private final Map<String, String> _components = new HashMap<>(); 051 052 private Logger _logger = LoggerFactory.getLogger(RuntimeConfig.class); 053 054 private String _contextPath; 055 056 private String _version; 057 private Date _buildDate; 058 059 /* External location of the kernel, if any */ 060 private File _externalKernel; 061 062 /* Locations of external plugins */ 063 private Map<String, File> _externalPlugins = new HashMap<>(); 064 065 /* Locations of external workspaces */ 066 private Map<String, File> _externalWorkspaces = new HashMap<>(); 067 068 private File _ametysHome; 069 070 private RuntimeConfig() 071 { 072 // empty constructor 073 } 074 075 /** 076 * Returns the shared instance of the <code>RuntimeConfig</code> 077 * @return the shared instance of the <code>RuntimeConfig</code> 078 */ 079 public static RuntimeConfig getInstance() 080 { 081 if (__config == null) 082 { 083 throw new IllegalStateException("RuntimeConfig has not been initialized."); 084 } 085 086 return __config; 087 } 088 089 /** 090 * Returns true if the Runtime has been configured (ie. if the {@link #configure(Configuration, Configuration, File, String)} method has been called. 091 * @return true if the Runtime has been configured. 092 */ 093 public static boolean isConfigured() 094 { 095 return __config != null; 096 } 097 098 /** 099 * Configures the Runtime kernel.<br> 100 * This method must be called <i>before</i> getting the RuntimConfig instance.<br><br> 101 * <b>Warning : the implementation allows this method to be called twice or more. This is only to allow the Runtime to be re-started dynamically.<br> 102 * Be aware that this can cause the application to become unstable.</b> 103 * @param runtimeConf the Configuration of the Runtime kernel (ie the contents of the WEB-INF/param/runtime.xml file) 104 * @param externalConf the Configuration of external locations (ie the contents of the WEB-INF/param/external-locations.xml file) 105 * @param ametysHome The ametys home directory 106 * @param contextPath the application context path 107 */ 108 public static synchronized void configure(Configuration runtimeConf, Configuration externalConf, File ametysHome, String contextPath) 109 { 110 __config = new RuntimeConfig(); 111 112 __config._contextPath = contextPath; 113 __config._ametysHome = ametysHome; 114 115 // create home directories 116 File dataHome = new File(ametysHome, AmetysHomeHelper.AMETYS_HOME_DATA_DIR); 117 dataHome.mkdirs(); 118 119 File configHome = new File(ametysHome, AmetysHomeHelper.AMETYS_HOME_CONFIG_DIR); 120 configHome.mkdirs(); 121 122 File tmpDir = new File(ametysHome, AmetysHomeHelper.AMETYS_HOME_TMP_DIR); 123 tmpDir.mkdirs(); 124 125 // runtimeConfig is null if the runtime.xml could not be read for any reason 126 if (runtimeConf != null) 127 { 128 __config._safeMode = false; 129 __config._initClass = runtimeConf.getChild("initClass").getValue(null); 130 131 __config._configureWorkspaces(runtimeConf.getChild("workspaces")); 132 __config._configurePlugins(runtimeConf.getChild("plugins")); 133 __config._configureComponents(runtimeConf.getChild("components")); 134 __config._configureApplication(runtimeConf.getChild("application")); 135 } 136 else 137 { 138 __config._safeMode = true; 139 __config._pluginsLocations.add("plugins/"); 140 } 141 142 if (externalConf != null) 143 { 144 __config._configureExternal(externalConf); 145 } 146 } 147 148 private void _configureWorkspaces(Configuration config) 149 { 150 _defaultWorkspace = config.getAttribute("default", null); 151 152 for (Configuration excluded : config.getChild("exclude").getChildren("workspace")) 153 { 154 String workspace = excluded.getValue(null); 155 156 if (workspace != null) 157 { 158 _excludedWorkspaces.add(workspace); 159 } 160 } 161 } 162 163 private void _configurePlugins(Configuration config) 164 { 165 for (Configuration excluded : config.getChild("exclude").getChildren("plugin")) 166 { 167 String plugin = excluded.getValue(null); 168 169 if (plugin != null) 170 { 171 _excludedPlugins.add(plugin); 172 } 173 } 174 175 for (Configuration excluded : config.getChild("exclude").getChildren("feature")) 176 { 177 String feature = excluded.getValue(null); 178 179 if (feature != null) 180 { 181 _excludedFeatures.add(feature); 182 } 183 } 184 185 for (Configuration locationConf : config.getChild("locations").getChildren("location")) 186 { 187 String location = locationConf.getValue(null); 188 189 if (location != null) 190 { 191 _pluginsLocations.add(location); 192 } 193 } 194 195 // On ajoute aux emplacements de plugins le répertoire "plugins" 196 if (!_pluginsLocations.contains("plugins") && !_pluginsLocations.contains("plugins/")) 197 { 198 _pluginsLocations.add("plugins/"); 199 } 200 201 } 202 203 private void _configureComponents(Configuration config) 204 { 205 for (Configuration extension : config.getChildren()) 206 { 207 String point = extension.getName(); 208 String id = extension.getValue(null); 209 210 if (id != null) 211 { 212 __config._components.put(point, id); 213 } 214 } 215 } 216 217 private void _configureApplication(Configuration config) 218 { 219 String version = config.getChild("version").getValue(""); 220 if (!"@VERSION@".equals(version) && !"VERSION".equals(version)) 221 { 222 _version = version; 223 } 224 225 String strDate = config.getChild("date").getValue(null); 226 227 if (strDate != null && !"".equals(strDate) && !"@DATE@".equals(strDate) && !"DATE".equals(strDate)) 228 { 229 try 230 { 231 _buildDate = new SimpleDateFormat("yyyyMMdd'T'HHmm z").parse(strDate); 232 } 233 catch (ParseException e) 234 { 235 _logger.warn("Unable to parse date '" + strDate + "' with format \"yyyyMMdd'T'HHmm z\". It will be ignored."); 236 } 237 } 238 } 239 240 private void _configureExternal(Configuration config) 241 { 242 String externalKernel = config.getChild("kernel").getValue(null); 243 _externalKernel = _getFile(externalKernel); 244 245 for (Configuration pluginConf : config.getChild("plugins").getChildren("plugin")) 246 { 247 String name = pluginConf.getAttribute("name", null); 248 String location = pluginConf.getValue(null); 249 250 if (name != null && location != null) 251 { 252 _externalPlugins.put(name, _getFile(location)); 253 } 254 } 255 256 for (Configuration workspaceConf : config.getChild("workspaces").getChildren("workspace")) 257 { 258 String name = workspaceConf.getAttribute("name", null); 259 String location = workspaceConf.getValue(null); 260 261 if (location != null) 262 { 263 _externalWorkspaces.put(name, _getFile(location)); 264 } 265 } 266 } 267 268 /* 269 * Returns the correspoding file, either absolute or relative to the context path 270 */ 271 private File _getFile(String path) 272 { 273 File file = path == null ? null : new File(path); 274 File result = file == null ? null : file.isAbsolute() ? file : new File(_contextPath, path); 275 return result; 276 } 277 278 /** 279 * Returns true if safe mode is needed (ie. if there's been an error reading runtime.xml). 280 * @return true if safe mode is needed. 281 */ 282 public boolean isSafeMode() 283 { 284 return _safeMode; 285 } 286 287 /** 288 * Returns the name of the default workspace. Null if none. 289 * @return the name of the default workspace 290 */ 291 public String getDefaultWorkspace() 292 { 293 return _defaultWorkspace; 294 } 295 296 /** 297 * Returns the name of the class to be excuted at the end of the initialization process, if any.<br> 298 * May be null. 299 * @return Returns the name of the class to be excuted at the end of the initialization process, if any 300 */ 301 public String getInitClassName() 302 { 303 return _initClass; 304 } 305 306 /** 307 * Returns a Collection containing the locations of the plugins 308 * @return a Collection containing the locations of the plugins 309 */ 310 public Collection<String> getPluginsLocations() 311 { 312 return _pluginsLocations; 313 } 314 315 /** 316 * Returns the declared external plugins (ie. not located in the webapp context). 317 * @return the declared external plugins 318 */ 319 public Map<String, File> getExternalPlugins() 320 { 321 return _externalPlugins; 322 } 323 324 /** 325 * Returns the declared external workspaces (ie. not located in the webapp context). 326 * @return the declared external workspaces 327 */ 328 public Map<String, File> getExternalWorkspaces() 329 { 330 return _externalWorkspaces; 331 } 332 333 /** 334 * Returns the absolute external location of the kernel, if any.<br> 335 * Returns null if the kernel is not externalized. 336 * @return the absolute external location of the kernel, if any. 337 */ 338 public File getExternalKernel() 339 { 340 return _externalKernel; 341 } 342 343 /** 344 * Returns a Collection containing the names of the excluded (deactivated) plugins 345 * @return a Collection containing the names of the excluded (deactivated) plugins 346 */ 347 public Collection<String> getExcludedPlugins() 348 { 349 return _excludedPlugins; 350 } 351 352 /** 353 * Returns a Collection containing the names of the excluded (deactivated) features 354 * @return a Collection containing the names of the excluded (deactivated) features 355 */ 356 public Collection<String> getExcludedFeatures() 357 { 358 return _excludedFeatures; 359 } 360 361 /** 362 * Returns a Collection containing the names of the excluded (deactivated) workspaces 363 * @return a Collection containing the names of the excluded (deactivated) workspaces 364 */ 365 public Collection<String> getExcludedWorkspaces() 366 { 367 return _excludedWorkspaces; 368 } 369 370 /** 371 * Returns a Map<role, component id> containing the choosen implementation for the given component role 372 * @return a Map<role, component id> containing the choosen implementation for the given component role 373 */ 374 public Map<String, String> getComponents() 375 { 376 return _components; 377 } 378 379 /** 380 * Returns the application version name 381 * @return the application version name 382 */ 383 public String getApplicationVersion() 384 { 385 return _version; 386 } 387 388 /** 389 * Returns the application build date, if provided. May be null. 390 * @return the application build date. 391 */ 392 public Date getApplicationBuildDate() 393 { 394 return _buildDate; 395 } 396 397 /** 398 * Returns the Ametys home directory. Cannot be null. 399 * @return The Ametys home directory. 400 */ 401 public File getAmetysHome() 402 { 403 return _ametysHome; 404 } 405}