/** * Copyright (C) 2012 52°North Initiative for Geospatial Open Source Software GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.n52.sos.cache; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.n52.sos.dataTypes.PropertyUnitMapping; import org.n52.sos.dataTypes.Unit; import org.n52.sos.db.AccessGDB; import org.n52.util.logging.Logger; public class PropertyUnitMappingCache extends AbstractEntityCache<PropertyUnitMapping> { private static final Logger logger = Logger .getLogger(PropertyUnitMappingCache.class.getName()); private static PropertyUnitMappingCache instance; private Map<Integer, Unit> propertyUnitMap = null; private Unit defaultFallbackUnit = new Unit(-1, "n/a", "n/a", "mg/m3", "n/a", "n/a"); public static synchronized PropertyUnitMappingCache instance(String dbName) throws FileNotFoundException { if (instance == null) { instance = new PropertyUnitMappingCache(dbName); } return instance; } private PropertyUnitMappingCache(String dbName) throws FileNotFoundException { super(dbName); } @Override protected String getCacheFileName() { return "propertyUnitMappings.cache"; } @Override protected String serializeEntity(PropertyUnitMapping entity) throws CacheException { logger.debug(String.format("Serializing %s mappings", entity.size())); if (entity.size() == 0) { throw new CacheException("No entries in PropertyUnitMappings! Check the database query"); } StringBuilder sb = new StringBuilder(); Integer valueFkUnit; for (Integer propertyId : entity.keySet()) { valueFkUnit = entity.get(propertyId); sb.append(propertyId); sb.append("="); sb.append(valueFkUnit); sb.append(";"); } sb.deleteCharAt(sb.length() - 1); return sb.toString(); } @Override protected PropertyUnitMapping deserializeEntity(String line) { PropertyUnitMapping result = new PropertyUnitMapping(); String[] entries = line.split(";"); String[] kvp; for (String e : entries) { kvp = e.split("="); try { Integer key = Integer.parseInt(kvp[0]); Integer value = Integer.parseInt(kvp[1]); result.put(key, value); } catch (NumberFormatException | IndexOutOfBoundsException ex) { logger.warn(ex.getMessage(), ex); } } logger.debug("Deserialized mapping: "+result.toString()); return result; } @Override protected Collection<PropertyUnitMapping> getCollectionFromDAO( AccessGDB geoDB) throws IOException { logger.info("Retrieving Mappings..."); return geoDB.getProcedureAccess().getPropertyUnitMappings(); } @Override protected AbstractEntityCache<PropertyUnitMapping> getSingleInstance() { return instance; } @Override public void updateCache(AccessGDB geoDB) throws CacheException, IOException { super.updateCache(geoDB); try { resolvePropertyUnitMappings(geoDB); } catch (CacheNotYetAvailableException e) { throw new CacheException(e); } } public synchronized Map<Integer, Unit> resolvePropertyUnitMappings(AccessGDB gdb) throws CacheNotYetAvailableException { if (propertyUnitMap != null && propertyUnitMap.isEmpty() && !requiresUpdate()) { logger.debug("returning in memory instance of propertyUnitMap"); return new HashMap<>(propertyUnitMap); } propertyUnitMap = new HashMap<>(); try { Map<Integer, Unit> units = gdb.getProcedureAccess() .getUnitsOfMeasure(); logger.debug("Available units: "+units.toString()); Map<String, PropertyUnitMapping> mappings = instance.getEntityCollection(gdb); logger.debug(String.format("PropertyUnitMapping entries from cache: %s", mappings.size())); for (String key : mappings.keySet()) { PropertyUnitMapping value = mappings.get(key); for (Integer propertyPk : value.keySet()) { propertyUnitMap.put(propertyPk, units.get(value.get(propertyPk))); } } logger.debug(String.format("PropertyUnitMappings resolved: %s (%s)", propertyUnitMap.size(), propertyUnitMap.toString())); } catch (IOException | NumberFormatException | CacheException e) { logger.warn("Failed to resolve property to unit mappings", e); } updateDefaultFallbackUnit(); return new HashMap<>(propertyUnitMap); } public Unit getDefaultFallbackUnit() { return defaultFallbackUnit; } private void updateDefaultFallbackUnit() { Collection<Unit> values = propertyUnitMap.values(); Unit max = null; int maxFrequency = 0; for (Unit u : values) { if (Collections.frequency(values, u) > maxFrequency) { max = u; } } if (max != null) { logger.debug("default fallback: "+ max); defaultFallbackUnit = max; } } @Override public void cancelCurrentExecution() { } }