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.SystemOfUnits;
27  
28  import org.hibernate.SessionFactory;
29  import org.jadira.usertype.spi.shared.AbstractParameterizedMultiColumnUserType;
30  import org.jadira.usertype.spi.shared.ColumnMapper;
31  import org.jadira.usertype.spi.shared.ValidTypesConfigured;
32  import org.jadira.usertype.spi.utils.reflection.ArrayUtils;
33  import org.jadira.usertype.spi.utils.reflection.ClassLoaderUtils;
34  import org.jadira.usertype.unitsofmeasurement.indriya.columnmapper.StringColumnStringMapper;
35  import org.jadira.usertype.unitsofmeasurement.indriya.columnmapper.StringColumnUnitMapper;
36  
37  import tec.units.indriya.quantity.Quantities;
38  import tec.units.indriya.unit.Units;
39  
40  /**
41   * Persists a Quantity using an arbitrary unit. Out of the box, the supported units are those defined in the generally used System of Units.
42   * 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
43   * list of class names.
44   */
45  public class PersistentQuantityAndUnit extends AbstractParameterizedMultiColumnUserType<Quantity<?>> implements ValidTypesConfigured<Unit<?>> {
46  
47  	private static final long serialVersionUID = -2015829087239519037L;
48  
49      private static final SystemOfUnits UNITS = Units.getInstance();
50      
51      private final Map<String, Unit<?>> unitsMap = new HashMap<String, Unit<?>>();
52      
53  	private List<Class<Unit<?>>> validTypes;
54  	
55      private static final ColumnMapper<?, ?>[] COLUMN_MAPPERS = new ColumnMapper<?, ?>[] { new StringColumnStringMapper(), new StringColumnUnitMapper() };
56  
57      private static final String[] PROPERTY_NAMES = new String[]{ "quantity", "unit" };
58      		
59      public PersistentQuantityAndUnit() {
60      	super();
61      	
62      	for (Unit<?> next : UNITS.getUnits()) {
63      		unitsMap.put(next.getSymbol(), next);
64          }
65  	}
66  	
67  	@Override
68  	public void applyConfiguration(SessionFactory sessionFactory) {
69  		super.applyConfiguration(sessionFactory);
70  		doApplyConfiguration();
71      }
72      
73  	private <Z> void doApplyConfiguration() {
74  
75  //		if (ValidTypesConfigured.class.isAssignableFrom(this.getClass())) {
76  		ValidTypesConfigured<Unit<?>> next = (ValidTypesConfigured<Unit<?>>)this;			
77  		performValidTypesConfiguration(next);
78  //		}
79  //		if (ValidTypesConfigured.class.isAssignableFrom(getColumnMapper().getClass())) {			
80  //		ValidTypesConfigured<Unit<?>> next = (ValidTypesConfigured<Unit<?>>)getColumnMapper();
81  //		performValidTypesConfiguration(next);
82  //		}
83  //		if (UnitConfigured.class.isAssignableFrom(this.getClass())) {
84  //		UnitConfigured unitConfigured = (UnitConfigured)this;			
85  //		performUnitConfiguration(unitConfigured);
86  //		}
87  	}
88  	
89  	private void performValidTypesConfiguration(ValidTypesConfigured<Unit<?>> next) {
90  		
91          String validTypesString = null;
92          if (getParameterValues() != null) {
93          	validTypesString = getParameterValues().getProperty("validTypes");
94          }
95  		if (validTypesString != null) {
96  			String[] validTypes = validTypesString.split(",");
97  			List<Class<Unit<?>>> units = new ArrayList<>();
98  			for (String nextType : validTypes) {
99  				
100 				
101 				try {
102 					@SuppressWarnings("unchecked")
103 					Class<Unit<?>> nextClass = (Class<Unit<?>>)(ClassLoaderUtils.classForName(nextType));
104 					units.add(nextClass);
105 				} catch (ClassNotFoundException e) {
106 					throw new IllegalStateException("Cannot find specified class " + nextType, e);
107 				}
108 				
109 			}
110 			next.setValidTypes(units);
111 		}
112 	}
113 
114 	@Override
115 	public void setValidTypes(List<Class<Unit<?>>> types) {
116 		for (Class<Unit<?>> next : types) {
117 			Unit<?> unit;
118 			try {
119 				unit = next.newInstance();
120 			} catch (InstantiationException | IllegalAccessException e) {
121 				throw new IllegalStateException("Cannot instantiate " + next.getName() + ": " + e.getMessage(), e);
122 			}
123 			unitsMap.put(unit.getSymbol(), unit);
124 		}
125 		this.validTypes = Collections.unmodifiableList(types);
126 	}
127 
128 	@Override
129 	public List<Class<Unit<?>>> getValidTypes() {
130 		return this.validTypes;
131 	}
132 	
133     @Override
134     protected Quantity<?> fromConvertedColumns(Object[] convertedColumns) {
135 
136         String stringPart = (String) convertedColumns[0];
137         Unit<?> unit = (Unit<?>) convertedColumns[1];
138 
139         return Quantities.getQuantity(stringPart + " " + unit.getSymbol());
140     }
141 
142     @Override
143     protected Object[] toConvertedColumns(Quantity<?> value) {
144         return new Object[] { value.getValue().toString(), value.getUnit() };
145     }
146     
147     @Override
148     protected ColumnMapper<?, ?>[] getColumnMappers() {
149         return COLUMN_MAPPERS;
150     }
151 
152     @Override
153     public String[] getPropertyNames() {
154         return ArrayUtils.copyOf(PROPERTY_NAMES);
155     }
156 
157 }