Java tutorial
/* * This file is part of rasdaman community. * * Rasdaman community is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Rasdaman community is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with rasdaman community. If not, see <http://www.gnu.org/licenses/>. * * Copyright 2003 - 2014 Peter Baumann / rasdaman GmbH. * * For more information please see <http://www.rasdaman.org> * or contact Peter Baumann via <baumann@rasdaman.com>. */ package petascope.util.ras; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import petascope.ConfigManager; import petascope.exceptions.ExceptionCode; import petascope.exceptions.PetascopeException; import petascope.exceptions.rasdaman.RasdamanException; /** * Keeps track of the types that exist in the tracked rasdaman instance. * * @author <a href="alex@flanche.net">Alex Dumitru</a> * @author <a href="vlad@flanche.net">Vlad Merticariu</a> */ public class TypeRegistry { private static TypeRegistry Instance = new TypeRegistry(); /** * Returns the instance to the singleton @link{TypeRegistry} * * @return */ public static TypeRegistry getInstance() throws PetascopeException { if (!initialized) { Instance.initializeRegistry(); initialized = true; } return Instance; } private TypeRegistry() { } /** * Returns the type entry for a give type name. * If the type is not in the database, an exception will be thrown. * * @param typeName the name of the type for which the entry is required * @return the type entry for the given type name * @throws petascope.util.ras.TypeRegistryEntryMissingException */ public TypeRegistryEntry getTypeEntry(String typeName) throws TypeRegistryEntryMissingException { TypeRegistryEntry type = typeRegistry.get(typeName); if (type == null) { throw new TypeRegistryEntryMissingException("Could not find the requested type: " + typeName); } return type; } public HashMap<String, TypeRegistryEntry> getTypeRegistry() { return typeRegistry; } private String generateStructStructure(ArrayList<String> bandBaseTypes) { String output = ""; int count = 0; for (String i : bandBaseTypes) { output += getRandomTypeName() + " " + i + " "; if (count < bandBaseTypes.size() - 1) { output += ","; } count++; } return output; } private String generateNullValuesRepresentation(ArrayList<String> nullValues) { String result = ""; if (!nullValues.isEmpty()) { String values = ""; int count = 0; for (String i : nullValues) { //check if i is an interval, if not (and is a single value), make it an interval, as there is a bug in // rasdaman which prevents adding single values as null values if (i.contains(":")) { values += i; } else { values += i + ":" + i; } //add "," on all but last dim if (count < nullValues.size() - 1) { values += ","; } count++; } result = NULL_VALUES_TEMPLATE.replace("$values", values); } return result; } private String expandDimensions(int numberOfDimensions) { StringBuilder result = new StringBuilder(); for (int i = 0; i < numberOfDimensions; i++) { result.append("a" + String.valueOf(i)); if (i < numberOfDimensions - 1) { result.append(","); } } return result.toString(); } public String createNewType(Integer numberOfDimensions, ArrayList<String> bandBaseTypes, ArrayList<String> nullValues) throws PetascopeException { log.info("Creating new type."); String marrayName = getRandomTypeName(); String setName = getRandomTypeName(); if (bandBaseTypes.size() == 1) { //simple types String queryMarray = QUERY_CREATE_MARRAY_TYPE.replace("$typeName", marrayName) .replace("$typeStructure", bandBaseTypes.get(0)) .replace("$dimensions", expandDimensions(numberOfDimensions)); //create the marray type RasUtil.executeRasqlQuery(queryMarray, ConfigManager.RASDAMAN_ADMIN_USER, ConfigManager.RASDAMAN_ADMIN_PASS, true); } else { //struct types String structName = getRandomTypeName(); String queryStruct = QUERY_CREATE_STRUCT_TYPE.replace("$structTypeName", structName) .replace("$structStructure", generateStructStructure(bandBaseTypes)); //create the struct type RasUtil.executeRasqlQuery(queryStruct, ConfigManager.RASDAMAN_ADMIN_USER, ConfigManager.RASDAMAN_ADMIN_PASS, true); //marray type String queryMarray = QUERY_CREATE_MARRAY_TYPE.replace("$typeName", marrayName) .replace("$typeStructure", structName) .replace("$dimensions", expandDimensions(numberOfDimensions)); //create it RasUtil.executeRasqlQuery(queryMarray, ConfigManager.RASDAMAN_ADMIN_USER, ConfigManager.RASDAMAN_ADMIN_PASS, true); } String querySet = QUERY_CREATE_SET_TYPE.replace("$typeName", setName).replace("$marrayTypeName", marrayName) .replace("$nullValues", generateNullValuesRepresentation(nullValues)); //create it RasUtil.executeRasqlQuery(querySet, ConfigManager.RASDAMAN_ADMIN_USER, ConfigManager.RASDAMAN_ADMIN_PASS, true); this.reinitialize(); return setName; } /** * Returns the mdd type for a given collection type. * * @param collectionType the collection type. * @return the mdd type, empty if nothing is found. */ public String getMddTypeForCollectionType(String collectionType) { String mddType = ""; for (Pair<String, String> i : setTypeDefinitions) { if (collectionType.equals(i.getKey())) { mddType = i.getValue(); break; } } return mddType; } /** * Generates a random alphabetic string * * @return */ private static String getRandomTypeName() { return RandomStringUtils.randomAlphabetic(GENERATED_TYPE_NAME_LENGTH); } /** * Collects the types from rasdl and inserts them into an internal registry */ private void initializeRegistry() throws PetascopeException { try { log.trace("Initializing the type registry"); initializeStructRegistry(); initializeMarrayTypes(); initializeSetTypes(); this.buildRegistry(); log.info("Succesfully initiated the type registry. Contents: {}", typeRegistry.toString()); } catch (RasdamanException e) { //log.error(MessageFormat.format("Could not read the rasdaman type registry. Tried with {0}rasdl -p", ConfigManager.RASDAMAN_BIN_PATH)); throw e; } } private void initializeSetTypes() throws RasdamanException { Object result = RasUtil.executeRasqlQuery(QUERY_SET_TYPES); RasQueryResult queryResult = new RasQueryResult(result); String[] fullStringResult = queryResult.toString().split("\0"); for (String setLine : fullStringResult) { String setName = parseSetName(setLine); String marrayName = parseSetMarrayName(setLine); String nilValues = parseSetNullValues(setLine); setTypeDefinitions.add(Pair.of(setName, marrayName)); setTypeNullValues.put(setName, nilValues); } } private String parseSetNullValues(String setLine) { String[] parts = setLine.split("NULL VALUES \\["); if (parts.length < 2) { //no nil values return ""; } String[] nilParts = parts[1].split("]"); if (nilParts.length < 1) { //invalid line return ""; } return nilParts[0].trim(); } private String parseSetName(String setLine) { String[] parts = setLine.split("CREATE TYPE "); if (parts.length < 2) { //invalid line return ""; } String[] setNameParts = parts[1].split(" "); if (setNameParts.length < 1) { //invalid line return ""; } return setNameParts[0].trim(); } private String parseSetMarrayName(String setLine) { String result; String[] parts = setLine.split("AS SET \\("); if (parts.length < 2) { //invalid line return ""; } String[] marrayNameParts = parts[1].split("\\)"); if (parts.length < 1) { //invalid line return ""; } if (marrayNameParts[0].contains("NULL VALUES")) { result = marrayNameParts[0].split("NULL VALUES")[0].trim(); } else { result = marrayNameParts[0].trim(); } return result; } private void initializeMarrayTypes() throws RasdamanException { Object result = RasUtil.executeRasqlQuery(QUERY_MARRAY_TYPES); RasQueryResult queryResult = new RasQueryResult(result); String[] fullStringResult = queryResult.toString().split("\0"); for (String marrayLine : fullStringResult) { String marrayName = parseMarrayName(marrayLine); String marrayStructure = parseMarrayStructure(marrayLine); marrayTypeDefinitions.put(marrayName, marrayStructure); } } private void initializeStructRegistry() throws RasdamanException { Object result = RasUtil.executeRasqlQuery(QUERY_STRUCT_TYPES); RasQueryResult queryResult = new RasQueryResult(result); String[] fullStringResult = queryResult.toString().split("\0"); for (String i : fullStringResult) { String[] parts = i.split("CREATE TYPE "); String typeName = ""; String typeStructure = ""; if (parts.length > 1) { String[] nameParts = parts[1].split(" "); if (nameParts.length > 0) { typeName = nameParts[0].trim(); } } String[] structParts = i.split("AS"); if (structParts.length > 1) { typeStructure = "struct " + structParts[1].trim().replace("(", "{").replace(")", "}"); } structTypeDefinitions.put(typeName, typeStructure); } } private String parseMarrayName(String marrayLine) { String[] parts = marrayLine.split("CREATE TYPE "); if (parts.length < 2) { //invalid line return ""; } String[] marrayParts = parts[1].split(" "); if (marrayParts.length < 1) { //invalid line return ""; } return marrayParts[0]; } private String parseMarrayStructure(String marrayLine) throws RasdamanException { String[] parts = marrayLine.split("AS"); if (parts.length < 2) { //invalid line return ""; } String marrayStructure = parts[1].trim(); String[] marrayStructureParts = marrayStructure.split("MDARRAY"); if (marrayStructureParts.length < 2) { //invalid line return ""; } //marrayStructureParts[0] is the type or structure name, marrayStructureParts[1] is the dimensionality return (expandStructureType(marrayStructureParts[0].trim()) + "," + marrayStructureParts[1].split(",").length); } private String expandStructureType(String typeName) throws RasdamanException { if (structTypeDefinitions.keySet().contains(typeName)) { return structTypeDefinitions.get(typeName); } else { return typeName; } } /** * @param line * @deprectaed Parses one rasdl line retrieving the base type and the domain type. We differentiate each line based on its contents * into two cases: * Marray definition: typedef marray <struct { char red, char green, char blue }, 2> RGBImage; * Set definition: typedef set <GreyImage> GreySet; */ private void parseRasdlLine(String line) { if (line.startsWith(RASDL_MARRAY_IDENTIFIER)) { String[] marrayParts = line.substring(RASDL_MARRAY_IDENTIFIER.length()).split(">"); if (marrayParts.length < 2) { //invalid line return; } String marrayName = marrayParts[1].replace(";", "").trim(); String marrayDef = marrayParts[0].replace("<", "").trim(); marrayTypeDefinitions.put(marrayName, marrayDef); } else if (line.startsWith(RASDL_SET_IDENTIFIER)) { String[] setParts = line.substring(RASDL_SET_IDENTIFIER.length()).split(">"); if (setParts.length < 2) { return; } String[] setNameWithNullValuesParts = setParts[1].replace(";", "").trim().split(" "); String setName = setNameWithNullValuesParts[setNameWithNullValuesParts.length - 1]; String marrayTypeName = setParts[0].replace(">", "").replace("<", "").trim(); setTypeDefinitions.add(Pair.of(setName, marrayTypeName)); } } private void reinitialize() throws PetascopeException { structTypeDefinitions.clear(); setTypeDefinitions.clear(); marrayTypeDefinitions.clear(); typeRegistry.clear(); initializeRegistry(); } /** * Builds the registry from the collected types gathered by parsing the rasdl output */ private void buildRegistry() { for (Pair<String, String> entry : setTypeDefinitions) { String domainType = marrayTypeDefinitions.get(entry.getValue()); if (domainType != null) { String[] domainTypeParts = domainType.split(","); if (domainTypeParts.length >= 2) { String[] baseTypeParts = ArrayUtils.remove(domainTypeParts, domainTypeParts.length - 1); String baseType = StringUtils.join(baseTypeParts, ""); String[] nullParts = setTypeNullValues.get(entry.getKey()).split(","); ArrayList<String> nullValues = new ArrayList<String>(); for (String i : nullParts) { if (!i.isEmpty()) { //if the value that is parsed is an interval with the same limits (e.g. 5:5), add only 1 //value. This is needed because currently there is a bug when creating types via rasql, //which doesn't allow single values to be specified. However, petascope needs to display single //values when presenting the output to the user. if (i.contains(":")) { String[] parts = i.split(":"); if (parts.length == 2 & parts[0].equals(parts[1])) { i = parts[0]; } } nullValues.add(i); } } typeRegistry.put(entry.getKey(), new TypeRegistryEntry(baseType, domainType, nullValues)); } } } } /** * Internal class for keeping track of the type entries */ public class TypeRegistryEntry { private TypeRegistryEntry(String baseType, String domainType, ArrayList<String> nullValues) { this.baseType = baseType; this.domainType = domainType; this.nullValues = nullValues; } /** * Returns the base type of this type entry * * @return */ public String getBaseType() { return baseType; } /** * Returns the domain type of this type entry * * @return */ public String getDomainType() { return domainType; } @Override public String toString() { return "TypeRegistryEntry{" + "baseType='" + baseType + '\'' + ", domainType='" + domainType + '\'' + ", nullValues='" + nullValues.toString() + "'" + '}'; } public Boolean equals(TypeRegistryEntry another) { return another.getBaseType().equals(this.baseType) && another.getDomainType().equals(this.domainType); } public ArrayList<String> getNullValues() { return nullValues; } private String baseType; private String domainType; private ArrayList<String> nullValues; } private final HashMap<String, TypeRegistryEntry> typeRegistry = new HashMap<String, TypeRegistryEntry>(); private final HashMap<String, String> marrayTypeDefinitions = new HashMap<String, String>(); private final ArrayList<Pair<String, String>> setTypeDefinitions = new ArrayList<Pair<String, String>>(); private HashMap<String, String> setTypeNullValues = new HashMap<String, String>(); private HashMap<String, String> structTypeDefinitions = new HashMap<String, String>(); private final String RASDL_MARRAY_IDENTIFIER = "typedef marray"; private final String RASDL_SET_IDENTIFIER = "typedef set"; private final Logger log = LoggerFactory.getLogger(TypeRegistry.class); private static boolean initialized = false; private final static Integer GENERATED_TYPE_NAME_LENGTH = 30; private final static String QUERY_MARRAY_TYPES = "SELECT a FROM RAS_MARRAY_TYPES a"; private final static String QUERY_STRUCT_TYPES = "SELECT a FROM RAS_STRUCT_TYPES a"; private final static String QUERY_SET_TYPES = "SELECT a FROM RAS_SET_TYPES a"; private final static String QUERY_CREATE_MARRAY_TYPE = "CREATE TYPE $typeName AS $typeStructure MDARRAY [$dimensions]"; private final static String QUERY_CREATE_SET_TYPE = "CREATE TYPE $typeName AS SET ($marrayTypeName $nullValues)"; private final static String NULL_VALUES_TEMPLATE = "NULL VALUES [$values]"; private final static String QUERY_CREATE_STRUCT_TYPE = "CREATE TYPE $structTypeName AS ( $structStructure )"; }