View Javadoc
1   /*
2    *  Copyright 2010, 2011, 2012 Christopher Pheby
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.jadira.usertype.unitsofmeasurement.indriya;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import javax.measure.Quantity;
25  import javax.measure.Unit;
26  import javax.measure.spi.ServiceProvider;
27  import javax.measure.spi.SystemOfUnitsService;
28  
29  import org.hibernate.SessionFactory;
30  import org.jadira.usertype.spi.shared.AbstractParameterizedUserType;
31  import org.jadira.usertype.spi.shared.ValidTypesConfigured;
32  import org.jadira.usertype.spi.utils.reflection.ClassLoaderUtils;
33  import org.jadira.usertype.unitsofmeasurement.indriya.columnmapper.StringColumnQuantityMapper;
34  import org.jadira.usertype.unitsofmeasurement.indriya.util.UnitConfigured;
35  
36  /**
37   * Persists a Quantity using the specified unit. Out of the box, the supported units are those defined in the generally used System of Units.
38   * If you want to add additional units, you must either specify them using the parameter 'validTypes', where they can be specified as a comma separated
39   * list of class names. Define the unit using its symbol via the parameter 'unit' - or, if the type has not been specified (or is built in), you can 
40   * also use its fully qualified class name.
41   */
42  public class  PersistentQuantity<Q extends Quantity<Q>> extends AbstractParameterizedUserType<Q, String, StringColumnQuantityMapper<Q>> implements ValidTypesConfigured<Unit<?>> {
43  
44  	private static final long serialVersionUID = -2015829087239519037L;
45      
46      private static final Map<String, Unit<?>> BASE_UNITS_MAP = new HashMap<String, Unit<?>>();
47  
48  	private static SystemOfUnitsService SYSTEM_OF_UNITS_SERVICE = ServiceProvider.current().getSystemOfUnitsService();
49      
50      static {
51          for (Unit<?> next : SYSTEM_OF_UNITS_SERVICE.getSystemOfUnits().getUnits()) {
52          	BASE_UNITS_MAP.put(next.getSymbol(), next);
53          }
54      }
55      
56      private static final Map<String, Unit<?>> unitsMap = new HashMap<String, Unit<?>>();
57      
58  	private List<Class<Unit<?>>> validTypes;
59      		
60      public PersistentQuantity() {
61      	super();
62  	}
63  	
64  	@Override
65  	public void applyConfiguration(SessionFactory sessionFactory) {
66  		super.applyConfiguration(sessionFactory);
67  		doApplyConfiguration();
68      }
69      
70  	private <Z> void doApplyConfiguration() {
71  
72  //		if (ValidTypesConfigured.class.isAssignableFrom(this.getClass())) {
73  		ValidTypesConfigured<Unit<?>> next = (ValidTypesConfigured<Unit<?>>)this;			
74  		performValidTypesConfiguration(next);
75  //		}
76  //		if (ValidTypesConfigured.class.isAssignableFrom(getColumnMapper().getClass())) {			
77  //		ValidTypesConfigured<Unit<?>> next = (ValidTypesConfigured<Unit<?>>)getColumnMapper();
78  //		performValidTypesConfiguration(next);
79  //		}
80  //		if (UnitConfigured.class.isAssignableFrom(this.getClass())) {
81  //		UnitConfigured unitConfigured = (UnitConfigured)this;			
82  //		performUnitConfiguration(unitConfigured);
83  //		}
84  		if (UnitConfigured.class.isAssignableFrom(getColumnMapper().getClass())) {
85  			UnitConfigured<?> unitConfigured = (UnitConfigured<?>)getColumnMapper();
86  			performUnitConfiguration(unitConfigured);
87  		}
88  	}
89  	
90  	@SuppressWarnings({ "rawtypes", "unchecked" })
91  	private void performUnitConfiguration(UnitConfigured<?> unitConfigured) {
92          String unitString = null;
93          if (getParameterValues() != null) {
94          	unitString = getParameterValues().getProperty("unit");
95          }
96  		if (unitString != null) {				
97  			try {
98  				Unit<?> unit = BASE_UNITS_MAP.get(unitString);
99  				
100 				if (unit == null) {
101 					unit = unitsMap.get(unitString);
102 				}
103 				if (unit == null) {
104 					final Class<Unit<?>> unitClass = (Class<Unit<?>>)(ClassLoaderUtils.classForName(unitString));
105 					final Unit<?> myUnit = unitClass.newInstance();
106 					unit = myUnit;
107 				}
108 				((StringColumnQuantityMapper) unitConfigured).setUnit(unit);
109 			} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
110 				throw new IllegalStateException("Cannot find specified class or unit " + unitString, e);
111 			}
112 		}
113 	}
114 	
115 	private void performValidTypesConfiguration(ValidTypesConfigured<Unit<?>> next) {
116 		
117         String validTypesString = null;
118         if (getParameterValues() != null) {
119         	validTypesString = getParameterValues().getProperty("validTypes");
120         }
121 		if (validTypesString != null) {
122 			String[] validTypes = validTypesString.split(",");
123 			List<Class<Unit<?>>> units = new ArrayList<>();
124 			for (String nextType : validTypes) {
125 				
126 				
127 				try {
128 					@SuppressWarnings("unchecked")
129 					Class<Unit<?>> nextClass = (Class<Unit<?>>)(ClassLoaderUtils.classForName(nextType));
130 					units.add(nextClass);
131 				} catch (ClassNotFoundException e) {
132 					throw new IllegalStateException("Cannot find specified class " + nextType, e);
133 				}
134 				
135 			}
136 			next.setValidTypes(units);
137 		}
138 	}
139 
140 	@Override
141 	public void setValidTypes(List<Class<Unit<?>>> types) {
142 		for (Class<Unit<?>> next : types) {
143 			Unit<?> unit;
144 			try {
145 				unit = next.newInstance();
146 			} catch (InstantiationException | IllegalAccessException e) {
147 				throw new IllegalStateException("Cannot instantiate " + next.getName() + ": " + e.getMessage(), e);
148 			}
149 			unitsMap.put(unit.getSymbol(), unit);
150 		}
151 		this.validTypes = Collections.unmodifiableList(types);
152 	}
153 
154 	@Override
155 	public List<Class<Unit<?>>> getValidTypes() {
156 		return this.validTypes;
157 	}
158 }