View Javadoc
1   /* ***************************************************************************
2    * Copyright (c) 2008 Brabenetz Harald, Austria.
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  
18  package org.settings4j.objectresolver;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.IOException;
22  import java.util.HashMap;
23  import java.util.Map;
24  import java.util.Properties;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.settings4j.ContentResolver;
28  import org.settings4j.ObjectResolver;
29  
30  /**
31   * Basic Connector implementations like getter and Setter of contentResolver, objectResolver.
32   * <p>
33   * 
34   * @author Harald.Brabenetz
35   *
36   */
37  public abstract class AbstractObjectResolver implements ObjectResolver {
38  
39      /** General Logger for this Class. */
40      private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(AbstractObjectResolver.class);
41  
42      /** The Key which ObjectResolver implementation should be used. */
43      public static final String PROP_OBJECT_RESOLVER_KEY = "objectResolverKey";
44      /** The Key if the found Object should be cached (this will handle the Object as singleton). */
45      public static final String PROP_CACHED = "cached";
46  
47      private String propertySuffix = ".properties";
48  
49      private final Map<String, Object> cachedObjects = new HashMap<String, Object>();
50  
51      private boolean cached = false;
52  
53      /** {@inheritDoc} */
54      public void addObjectResolver(final ObjectResolver objectResolver) {
55          throw new UnsupportedOperationException(this.getClass().getName() + " cannot add other ObjectResolvers");
56      }
57  
58      /** {@inheritDoc} */
59      public Object getObject(final String key, final ContentResolver contentResolver) {
60  
61          Object result = this.cachedObjects.get(key);
62          if (result != null) {
63              return result;
64          }
65  
66  
67          final byte[] content = contentResolver.getContent(key);
68          if (content != null) {
69              final Properties properties = getObjectProperties(key, contentResolver);
70              if (properties != null) {
71                  final String propObjectResolverKey = properties.getProperty(PROP_OBJECT_RESOLVER_KEY);
72                  final String propCached = properties.getProperty(PROP_CACHED);
73                  if (StringUtils.isEmpty(propObjectResolverKey)) {
74                      LOG.warn("The property-File for Key '{}' doesn't have the required Property '{}'", //
75                          key, PROP_OBJECT_RESOLVER_KEY);
76                      return null;
77                  }
78  
79                  if (getObjectResolverKey().equals(propObjectResolverKey)) {
80                      result = contentToObject(key, properties, content, contentResolver);
81                      if (result != null) {
82                          if ("true".equalsIgnoreCase(propCached) || (propCached == null && isCached())) {
83                              this.cachedObjects.put(key, result);
84                          }
85                          return result;
86                      }
87                  }
88              }
89          }
90          return null;
91      }
92  
93      /**
94       * To get the additional Properties for the given byte[] content can be overwriten by subclasses.
95       * <p>
96       * The default implementation reads the PropertyFile from key + ".properties".
97       * If no property where found, or an error occurs, this method return null.
98       * 
99       * @param key the key of the byte[] Content to convert.
100      * @param contentResolver the ContentResolver to read the additional Property-File.
101      * @return the parsed {@link Properties} Object or null if an error occurred.
102      */
103     protected Properties getObjectProperties(final String key, final ContentResolver contentResolver) {
104 
105         final byte[] propertyContent = contentResolver.getContent(key + this.propertySuffix);
106         if (propertyContent == null) {
107             return null;
108         }
109         // else
110         final Properties properties = new Properties();
111         try {
112             properties.load(new ByteArrayInputStream(propertyContent));
113         } catch (final IOException e) {
114             LOG.error(e.getMessage(), e);
115             return null;
116         }
117         return properties;
118         
119     }
120 
121     public String getPropertySuffix() {
122         return this.propertySuffix;
123     }
124 
125     public void setPropertySuffix(final String propertySuffix) {
126         this.propertySuffix = propertySuffix;
127     }
128 
129     protected String getObjectResolverKey() {
130         return this.getClass().getName();
131     }
132 
133     /**
134      * Method to convert the given content-File to an Object must be implemented by SubClasses.
135      * <p>
136      * 
137      * @param key The Original Key of the Object
138      * @param properties The Property-File which where Found under key + ".properties"
139      * @param content The byte[] Content to convert.
140      * @param contentResolver the contentResolver to get possible additional content Files.
141      * @return the parsed Object from the byte[] Content.
142      */
143     protected abstract Object contentToObject(String key, Properties properties, byte[] content,
144             ContentResolver contentResolver);
145 
146     public boolean isCached() {
147         return this.cached;
148     }
149 
150     public void setCached(final boolean cached) {
151         this.cached = cached;
152     }
153 }