package rocks.inspectit.shared.all.serializer.schema; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.builder.ToStringBuilder; import org.slf4j.Logger; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; import rocks.inspectit.shared.all.serializer.impl.SerializationManager; import rocks.inspectit.shared.all.spring.logger.Log; /** * {@link ClassSchemaManager} holds all schemas that are defined, and provides them to the * {@link SerializationManager}. * * @author Ivan Senic * */ @Component public class ClassSchemaManager implements InitializingBean { /** * The log of this class. */ @Log Logger log; /** * Default directory location of all schemas. */ public static final String SCHEMA_DIR = "schema"; /** * The file name where list of schemas are. This file is supposed to be in default schema * directory. */ public static final String SCHEMA_LIST_FILE = "schemaList.txt"; /** * Schemas mapped to the class names. */ private Map<String, ClassSchema> schemaMap = new HashMap<String, ClassSchema>(); /** * Resource of the schema list file. */ @Value("classpath:" + SCHEMA_DIR + "/" + SCHEMA_LIST_FILE) private Resource schemaListFile; /** * Adds one {@link ClassSchema} to the {@link ClassSchemaManager}. * * @param schema * Schema to be added. Note that the class name inside schema has to be defined, for * schema to be added. */ public void addSchema(ClassSchema schema) { if (schema != null) { if (schemaMap == null) { schemaMap = new HashMap<String, ClassSchema>(); } schemaMap.put(schema.getClassName(), schema); } } /** * Gets {@link ClassSchema} for a class name. * * @param className * Name of the class schema is needed. * @return Schema or null if schema for the class is not present in schema manager. */ public ClassSchema getSchema(String className) { return schemaMap.get(className); } /** * Loads schemas. * * @throws IOException * If {@link IOException} occurs. */ public void loadSchemasFromLocations() throws IOException { log.info("||-Class Schema Manager started.."); InputStream is = schemaListFile.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); ClassLoader classLoader = ClassSchemaManager.class.getClassLoader(); String schemaLocation = br.readLine(); while (null != schemaLocation) { InputStream inputStream = classLoader.getResourceAsStream(schemaLocation); if (null == inputStream) { throw new IllegalArgumentException("Schema file '" + schemaLocation + "' can not be found."); } InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); loadSchemaFromReader(bufferedReader); schemaLocation = br.readLine(); if (null != bufferedReader) { bufferedReader.close(); } if (null != inputStreamReader) { inputStreamReader.close(); } if (null != inputStream) { inputStream.close(); } } br.close(); isr.close(); is.close(); } /** * Loads all schemas from a given directory. * * @param directory * File that points to the directory. */ protected void loadSchemas(File directory) { if (!directory.isDirectory()) { throw new IllegalArgumentException("Schemas can not be loaded. Provided file is not a directory."); } File[] files = directory.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String fileName) { return fileName.endsWith(ClassSchema.SCHEMA_EXT); } }); if (files != null) { loadSchemas(files); } } /** * Load schemas from schemas files. * * @param files * Array of schema files. */ protected void loadSchemas(File[] files) { for (File file : files) { FileReader fileReader = null; BufferedReader reader = null; try { fileReader = new FileReader(file); reader = new BufferedReader(fileReader); loadSchemaFromReader(reader); } catch (IOException exception) { log.warn("Exception occurred during reading the schema file.", exception); } finally { try { if (reader != null) { reader.close(); } if (fileReader != null) { fileReader.close(); } } catch (IOException exception) { log.warn("Exception occurred trying to close the schema file,", exception); } } } } /** * Loads schema from a {@link BufferedReader}. It is responsibility of a caller to close the * reader. * * @param reader * BufferReader. * @throws IOException * If {@link IOException} occurs. */ private void loadSchemaFromReader(BufferedReader reader) throws IOException { if (reader != null) { Map<String, String> schemaInitMap = new HashMap<String, String>(); String line = reader.readLine(); while (line != null) { if ((line.length() > 0) && (line.charAt(0) != '#')) { String[] tokens = line.split(":"); if (tokens.length == 2) { schemaInitMap.put(tokens[0].trim(), tokens[1].trim()); } } line = reader.readLine(); } ClassSchema schema = new ClassSchema(schemaInitMap); this.addSchema(schema); if (log.isDebugEnabled()) { log.info("||-Successfully loaded schema for class " + schema.getClassName()); } } } /** * @return the schemaMap Returns the unmodifiable schema map. */ public Map<String, ClassSchema> getSchemaMap() { return Collections.unmodifiableMap(schemaMap); } /** * @param schemaListFile * the schemaListFile to set */ public void setSchemaListFile(Resource schemaListFile) { this.schemaListFile = schemaListFile; } /** * {@inheritDoc} */ @Override public void afterPropertiesSet() throws Exception { loadSchemasFromLocations(); } /** * Sets {@link #log}. * * @param log * New value for {@link #log} */ public void setLog(Logger log) { this.log = log; } /** * {@inheritDoc} */ @Override public String toString() { ToStringBuilder toStringBuilder = new ToStringBuilder(this); toStringBuilder.append("schemaMap", schemaMap); return toStringBuilder.toString(); } }