View Javadoc
1   /*
2    * Copyright 2011 the original author or authors.
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  package org.openehealth.ipf.commons.core;
17  
18  import org.openehealth.ipf.commons.core.config.TypeConverter;
19  import org.slf4j.Logger;
20  import org.slf4j.LoggerFactory;
21  
22  import javax.xml.bind.annotation.XmlTransient;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  /**
27   * Content map based on Spring type conversion framework.
28   * @author Dmytro Rud
29   */
30  @XmlTransient
31  public class ContentMap {
32      private static transient Logger LOG = LoggerFactory.getLogger(ContentMap.class);
33  
34      // synchronized manually
35      private transient final Map<Class<?>, Object> map = new HashMap<>();
36  
37      private static transient TypeConverter conversionService;
38  
39  
40      /**
41       * Returns document content of the given type.
42       * @param targetType
43       *      desired content type.
44       * @param <T>
45       *      inferred desired content type.
46       * @return
47       *      content of the given type, or <code>null</code> when content of the
48       *      desired type is neither already present nor can be automatically
49       *      generated from an existing one.
50       */
51      @SuppressWarnings("unchecked")
52      public <T> T getContent(Class<T> targetType) {
53          T result = (T) map.get(targetType);
54          if (result != null) {
55              LOG.debug("Return existing content of type " + targetType);
56              return result;
57          }
58  
59          if (conversionService == null) {
60              LOG.debug("Conversion service not configured");
61              return null;
62          }
63  
64          synchronized (map) {
65              // TODO: optimise conversion using some sophisticated iteration ordering ???
66              for (Class<?> sourceType : map.keySet()) {
67                  if (conversionService.canConvert(sourceType, targetType)) {
68                      result = conversionService.convert(map.get(sourceType), targetType);
69                      if (result != null) {
70                          LOG.debug("Successfully generated " + targetType + " from " + sourceType);
71                          setContent(targetType, result);
72                          return result;
73                      }
74                  }
75              }
76          }
77  
78          LOG.debug("Could not find appropriate converter for the target type " + targetType);
79          return null;
80      }
81  
82      /**
83       * Adds or replaces document content of the given type.
84       * @param key
85       *      content type.
86       * @param content
87       *      content; <code>null</code> values are not allowed.
88       * @param <T>
89       *      inferred content type.
90       * @return
91       *      the given content, as convenience.
92       */
93      @SuppressWarnings("unchecked")
94      public <T> T setContent(Class<T> key, T content) {
95          if (key == null) throw new IllegalArgumentException("content type must be provided");
96          if (content == null) throw new IllegalArgumentException("null content is not allowed");
97          synchronized (map) {
98              return (T) map.put(key, content);
99          }
100     }
101 
102 
103     /**
104      * Removes (invalidates) document content of the given type.
105      * @param key
106      *      content type.
107      * @param <T>
108      *      inferred content type.
109      * @return
110      *      Obsolete content of the given type, or <code>null</code>,
111      *      when no content of the given type was present.
112      */
113     @SuppressWarnings("unchecked")
114     public <T> T removeContent(Class<T> key) {
115         synchronized (map) {
116             return (T) map.remove(key);
117         }
118     }
119 
120 
121     /**
122      * Returns <code>true</code> when this content map already contains
123      * an element of the given type.
124      */
125     public boolean hasContent(Class<?> key) {
126         return map.containsKey(key);
127     }
128 
129 
130     /**
131      * Returns count of currently available content types in this content map.
132      */
133     public int getContentsCount() {
134         return map.size();
135     }
136 
137 
138     /**
139      * Returns conversion service for document contents.
140      */
141     public static TypeConverter getConversionService() {
142         return conversionService;
143     }
144 
145 
146     /**
147      * Sets conversion service for document contents.
148      */
149     public static void setConversionService(TypeConverter conversionService) {
150         ContentMap.conversionService = conversionService;
151     }
152 
153 }