001/**
002 * Copyright 2014 Tampere University of Technology, Pori Department
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 core.tut.pori.properties;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.util.Date;
021import java.util.HashMap;
022import java.util.Iterator;
023import java.util.Map;
024import java.util.Properties;
025
026import javax.servlet.ServletContext;
027
028import org.apache.log4j.Logger;
029import org.springframework.context.support.ClassPathXmlApplicationContext;
030
031import core.tut.pori.context.RESTHandler;
032import core.tut.pori.utils.StringUtils;
033
034/**
035 * The system property handler.
036 * 
037 * This class can be used to retrieve system property files known by the system.
038 * 
039 * One should not initialize this handler directly, as an instantiated version is available from ServiceInitializer.
040 */
041public final class PropertyHandler {
042  private static final Logger LOGGER = Logger.getLogger(PropertyHandler.class);
043  private static final String PROPERTIES_CONFIGURATION_FILE = "properties-context.xml";
044  /* services */
045  private String _bindContext = null;
046  private String _restBindContext = null;
047  private ClassPathXmlApplicationContext _context = null;
048  private Map<Class<?>,SystemProperty> _properties = null;
049  
050  /**
051   * @param context 
052   * 
053   */
054  public PropertyHandler(ServletContext context){
055    LOGGER.debug("Initializing handler...");
056    Date started = new Date();
057    _context = new ClassPathXmlApplicationContext(core.tut.pori.properties.SystemProperty.CONFIGURATION_FILE_PATH+PROPERTIES_CONFIGURATION_FILE);
058    LOGGER.debug("Class Path XML Context initialized in "+StringUtils.getDurationString(started, new Date()));
059    
060    loadProperties(context);
061    LOGGER.debug("Property Handler initialized in "+StringUtils.getDurationString(started, new Date()));
062  }
063  
064  /**
065   * @param context
066   * @throws IllegalArgumentException
067   */
068  private void loadProperties(ServletContext context) throws IllegalArgumentException{
069    ClassLoader classLoader = getClass().getClassLoader();
070    try (InputStream systemStream = classLoader.getResourceAsStream(SystemProperty.SYSTEM_PROPERTY_FILE)) {
071      Properties systemProperties = new Properties();
072      systemProperties.load(systemStream);
073      systemProperties = UnmodifiableProperties.unmodifiableProperties(systemProperties);
074      _bindContext = systemProperties.getProperty(SystemProperty.PROPERTY_SERVICE_PORI_PROPERTIES_BIND_ADDRESS)+context.getContextPath()+"/";
075      _restBindContext = _bindContext + RESTHandler.PATH_REST;
076      
077      Map<String, SystemProperty> propertyMap = _context.getBeansOfType(SystemProperty.class);
078      if(propertyMap == null || propertyMap.isEmpty()){
079        LOGGER.debug("No properties to initialize.");
080        return;
081      }
082      int size = propertyMap.size();
083      LOGGER.debug("Found "+size+" SystemProperties.");
084      
085      _properties = new HashMap<>(size);
086      for(Iterator<SystemProperty> iter = propertyMap.values().iterator();iter.hasNext();){
087        SystemProperty property = iter.next();
088        String propertyFilePath = property.getPropertyFilePath();
089        if(propertyFilePath != null && !propertyFilePath.equals(SystemProperty.SYSTEM_PROPERTY_FILE)){  // check if custom property file location has been given
090          LOGGER.debug("Found property with custom file path.");
091          Properties customProperties = new Properties();
092          try (InputStream customStream = classLoader.getResourceAsStream(propertyFilePath)) {
093            if(customStream == null){
094              throw new IllegalArgumentException("Failed to load custom property file: "+propertyFilePath+", for "+property.getClass().toString());
095            }
096            customProperties.load(customStream);
097            property.initialize(customProperties);
098          }
099        }else{
100          property.initialize(systemProperties);
101        }
102        _properties.put(property.getClass(), property);
103      //  String confi
104      }
105    } catch (IOException ex) {
106      LOGGER.error(ex, ex);
107      throw new IllegalArgumentException("Failed to read property file.");
108    }
109  }
110  
111  /**
112   * Get the defined URL e.g. https://example.org/context/
113   * @return bind context of the service
114   */
115  public String getBindContext() {
116    return _bindContext;
117  }
118  
119  /**
120   * Get the defined URL e.g. https://example.org/context/rest/
121   * @return REST bind context of the service
122   */
123  public String getRESTBindContext() {
124    return _restBindContext;
125  }
126
127  /**
128   * Do NOT close or cleanup the instances returned by this method, the initialization and destruction is handled automatically.
129   * 
130   * @param cls 
131   * @return system properties of the given class or null if not found
132   */
133  @SuppressWarnings("unchecked")
134  public <T extends SystemProperty> T getSystemProperties(Class<T> cls) {
135    return (T) (_properties == null ? null : _properties.get(cls));
136  }
137  
138  /**
139   * close this handler and release all resources
140   */
141  public void close(){
142    _bindContext = null;
143    _restBindContext = null;
144    _properties = null;
145    _context.close();
146    _context = null;
147  }
148}