Java tutorial
/** * Copyright (c) 2010-2017 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package de.csdev.ebus.cfg.std; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.net.URL; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import de.csdev.ebus.cfg.EBusConfigurationReaderException; import de.csdev.ebus.cfg.IEBusConfigurationReader; import de.csdev.ebus.cfg.std.dto.EBusCollectionDTO; import de.csdev.ebus.cfg.std.dto.EBusCommandDTO; import de.csdev.ebus.cfg.std.dto.EBusCommandMethodDTO; import de.csdev.ebus.cfg.std.dto.EBusCommandTemplatesDTO; import de.csdev.ebus.cfg.std.dto.EBusValueDTO; import de.csdev.ebus.command.EBusCommand; import de.csdev.ebus.command.EBusCommandCollection; import de.csdev.ebus.command.EBusCommandMethod; import de.csdev.ebus.command.EBusCommandNestedValue; import de.csdev.ebus.command.EBusCommandValue; import de.csdev.ebus.command.IEBusCommandCollection; import de.csdev.ebus.command.IEBusCommandMethod; import de.csdev.ebus.command.datatypes.EBusTypeRegistry; import de.csdev.ebus.command.datatypes.IEBusType; import de.csdev.ebus.command.datatypes.ext.EBusTypeBytes; import de.csdev.ebus.utils.EBusUtils; /** * @author Christian Sowada - Initial contribution * */ public class EBusConfigurationReader implements IEBusConfigurationReader { private final Logger logger = LoggerFactory.getLogger(EBusConfigurationReader.class); private EBusTypeRegistry registry; private Map<String, Collection<EBusCommandValue>> templateValueRegistry = new HashMap<String, Collection<EBusCommandValue>>(); private Map<String, Collection<EBusCommandValue>> templateBlockRegistry = new HashMap<String, Collection<EBusCommandValue>>(); /* * (non-Javadoc) * * @see de.csdev.ebus.cfg.IEBusConfigurationReader#loadBuildInConfigurations() */ @Override public List<IEBusCommandCollection> loadBuildInConfigurationCollections() { return loadConfigurationCollectionBundle( EBusConfigurationReader.class.getResource("/index-configuration.json")); } /* * (non-Javadoc) * * @see de.csdev.ebus.cfg.IEBusConfigurationReader#loadConfigurationCollection(java.io.InputStream) */ @Override public IEBusCommandCollection loadConfigurationCollection(URL url) throws IOException, EBusConfigurationReaderException { if (registry == null) { throw new RuntimeException("Unable to load configuration without EBusType set!"); } if (url == null) { throw new IllegalArgumentException("Required argument url is null!"); } Type merchantListType = new TypeToken<List<EBusValueDTO>>() { }.getType(); Gson gson = new Gson(); gson = new GsonBuilder().registerTypeAdapter(merchantListType, new EBusValueJsonDeserializer()).create(); MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new IOException(e); } // collect md5 hash while reading file DigestInputStream dis = new DigestInputStream(url.openStream(), md); EBusCollectionDTO collection = gson.fromJson(new InputStreamReader(dis), EBusCollectionDTO.class); EBusCommandCollection commandCollection = new EBusCommandCollection(collection.getId(), collection.getLabel(), collection.getDescription(), collection.getProperties()); // add md5 hash commandCollection.setSourceHash(md.digest()); commandCollection.setIdentification(collection.getIdentification()); // parse the template block parseTemplateConfiguration(collection); if (collection.getCommands() != null) { for (EBusCommandDTO commandDto : collection.getCommands()) { if (commandDto != null) { commandCollection.addCommand(parseTelegramConfiguration(commandCollection, commandDto)); } } } return commandCollection; } protected void parseTemplateConfiguration(EBusCollectionDTO collection) throws EBusConfigurationReaderException { // extract templates List<EBusCommandTemplatesDTO> templateSection = collection.getTemplates(); if (templateSection != null) { for (EBusCommandTemplatesDTO templates : templateSection) { List<EBusValueDTO> templateValues = templates.getTemplate(); if (templateValues != null) { Collection<EBusCommandValue> blockList = new ArrayList<EBusCommandValue>(); for (EBusValueDTO value : templateValues) { Collection<EBusCommandValue> pv = parseValueConfiguration(value, null, null); blockList.addAll(pv); // global id String id = collection.getId() + "." + templates.getName() + "." + value.getName(); logger.trace("Add template with global id {} to registry ...", id); templateValueRegistry.put(id, pv); } String id = collection.getId() + "." + templates.getName(); // global id logger.trace("Add template block with global id {} to registry ...", id); templateBlockRegistry.put(id, blockList); } } } } /** * @param commandCollection * @param commandElement * @return * @throws EBusConfigurationReaderException */ protected EBusCommand parseTelegramConfiguration(IEBusCommandCollection commandCollection, EBusCommandDTO commandElement) throws EBusConfigurationReaderException { if (commandElement == null) { throw new IllegalArgumentException("Parameter \"command dto\" not set!"); } LinkedHashMap<String, EBusCommandValue> templateMap = new LinkedHashMap<String, EBusCommandValue>(); // collect available channels List<String> methods = new ArrayList<String>(); if (commandElement.getGet() != null) { methods.add("get"); } if (commandElement.getSet() != null) { methods.add("set"); } if (commandElement.getBroadcast() != null) { methods.add("broadcast"); } // extract default values String id = commandElement.getId(); byte[] command = EBusUtils.toByteArray(commandElement.getCommand()); String label = commandElement.getLabel(); String device = commandElement.getDevice(); Byte destination = EBusUtils.toByte(commandElement.getDst()); Byte source = EBusUtils.toByte(commandElement.getSrc()); // read in template block if (commandElement.getTemplate() != null) { for (EBusValueDTO template : commandElement.getTemplate()) { for (EBusCommandValue templateCfg : parseValueConfiguration(template, null, null)) { templateMap.put(templateCfg.getName(), templateCfg); } } } EBusCommand cfg = new EBusCommand(); cfg.setId(id); cfg.setLabel(label); cfg.setDevice(device); cfg.setParentCollection(commandCollection); // loop all available channnels for (String channel : methods) { EBusCommandMethodDTO commandMethodElement = null; IEBusCommandMethod.Method method = null; if (channel.equals("get")) { commandMethodElement = commandElement.getGet(); method = IEBusCommandMethod.Method.GET; } else if (channel.equals("set")) { commandMethodElement = commandElement.getSet(); method = IEBusCommandMethod.Method.SET; } else if (channel.equals("broadcast")) { commandMethodElement = commandElement.getBroadcast(); method = IEBusCommandMethod.Method.BROADCAST; } if (commandMethodElement != null) { EBusCommandMethod commandMethod = new EBusCommandMethod(cfg, method); // overwrite with local command if (StringUtils.isNotEmpty(commandMethodElement.getCommand())) { commandMethod.setCommand(EBusUtils.toByteArray(commandMethodElement.getCommand())); } else { commandMethod.setCommand(command); } commandMethod.setDestinationAddress(destination); commandMethod.setSourceAddress(source); if (commandMethodElement.getMaster() != null) { for (EBusValueDTO template : commandMethodElement.getMaster()) { for (EBusCommandValue ev : parseValueConfiguration(template, templateMap, commandMethod)) { commandMethod.addMasterValue(ev); } } } if (commandMethodElement.getSlave() != null) { for (EBusValueDTO template : commandMethodElement.getSlave()) { for (EBusCommandValue ev : parseValueConfiguration(template, templateMap, commandMethod)) { commandMethod.addSlaveValue(ev); } } } } } return cfg; } /** * @param template * @param templateMap * @param commandMethod * @return * @throws EBusConfigurationReaderException */ protected Collection<EBusCommandValue> parseValueConfiguration(EBusValueDTO template, Map<String, EBusCommandValue> templateMap, EBusCommandMethod commandMethod) throws EBusConfigurationReaderException { Collection<EBusCommandValue> result = new ArrayList<EBusCommandValue>(); String typeStr = template.getType(); String collectionId = null; // check if really set if (commandMethod != null && commandMethod.getParent() != null && commandMethod.getParent().getParentCollection() != null) { collectionId = commandMethod.getParent().getParentCollection().getId(); } if (typeStr.equals("template-block")) { Collection<EBusCommandValue> templateCollection = null; if (StringUtils.isNotEmpty(template.getName())) { logger.warn("Property 'name' is not allowed for type 'template-block', ignore property !"); } // use the global or local id as template block, new with alpha 15 String id = (String) template.getProperty("id"); String globalId = collectionId + "." + id; if (StringUtils.isNotEmpty(id)) { templateCollection = templateBlockRegistry.get(id); if (templateCollection == null) { // try to convert the local id to a global id logger.trace("Unable to find a template with id {}, second try with {} ...", id, globalId); templateCollection = templateBlockRegistry.get(globalId); if (templateCollection == null) { throw new EBusConfigurationReaderException("Unable to find a template-block with id {0}!", id); } } } else if (templateMap != null) { // return the complete template block from within command block templateCollection = templateMap.values(); } else { throw new EBusConfigurationReaderException( "No additional information for type 'template-block' defined!"); } if (templateCollection != null) { for (EBusCommandValue commandValue : templateCollection) { // clone the original value EBusCommandValue clone = commandValue.clone(); clone.setParent(commandMethod); overwritePropertiesFromTemplate(clone, template); result.add(clone); } } return result; } else if (typeStr.equals("template")) { String id = (String) template.getProperty("id"); String globalId = collectionId + "." + id; Collection<EBusCommandValue> templateCollection = null; if (StringUtils.isEmpty(id)) { throw new EBusConfigurationReaderException( "No additional information for type 'template' defined!"); } if (templateValueRegistry.containsKey(id)) { templateCollection = templateValueRegistry.get(id); } else if (templateValueRegistry.containsKey(globalId)) { templateCollection = templateValueRegistry.get(globalId); } else if (templateMap != null && templateMap.containsKey(id)) { // return the complete template block from within command block templateCollection = new ArrayList<EBusCommandValue>(); templateCollection.add(templateMap.get(id)); } else { throw new EBusConfigurationReaderException("Unable to find a template for id {0}!", id); } if (templateCollection != null && !templateCollection.isEmpty()) { for (EBusCommandValue commandValue : templateCollection) { EBusCommandValue clone = commandValue.clone(); clone.setParent(commandMethod); overwritePropertiesFromTemplate(clone, template); // allow owerwrite for single names clone.setName(StringUtils.defaultIfEmpty(template.getName(), clone.getName())); result.add(clone); } } else { throw new EBusConfigurationReaderException("Internal template collection is empty!"); } return result; } else if (typeStr.equals("static")) { // convert static content to bytes byte[] byteArray = EBusUtils.toByteArray(template.getDefault()); Map<String, Object> properties = new HashMap<String, Object>(); properties.put("length", byteArray.length); final IEBusType<?> typeByte = registry.getType(EBusTypeBytes.TYPE_BYTES, properties); EBusCommandValue commandValue = EBusCommandValue.getInstance(typeByte, byteArray); commandValue.setParent(commandMethod); result.add(commandValue); return result; } EBusCommandValue ev = null; // value is a nested value if (template.getChildren() != null) { EBusCommandNestedValue evc = new EBusCommandNestedValue(); ev = evc; int pos = 0; for (EBusValueDTO childElem : template.getChildren()) { // add pos information from list childElem.setPos(pos); // parse child value for (EBusCommandValue childValue : parseValueConfiguration(childElem, templateMap, commandMethod)) { evc.add(childValue); } pos++; } } else { // default value ev = new EBusCommandValue(); } Map<String, Object> map = template.getAsMap(); IEBusType<?> type = registry.getType(typeStr, map); ev.setType(type); ev.setName(template.getName()); ev.setLabel(template.getLabel()); ev.setFactor(template.getFactor()); ev.setMin(template.getMin()); ev.setMax(template.getMax()); ev.setMapping(template.getMapping()); ev.setFormat(template.getFormat()); ev.setParent(commandMethod); result.add(ev); return result; } private void overwritePropertiesFromTemplate(EBusCommandValue clone, EBusValueDTO template) { // allow placeholders in template-block mode if (StringUtils.isNotEmpty(template.getLabel())) { if (StringUtils.isNotEmpty(clone.getLabel()) && clone.getLabel().contains("%s")) { clone.setLabel(String.format(clone.getLabel(), template.getLabel())); } else { clone.setLabel(template.getLabel()); } } // clone.setName(StringUtils.defaultIfEmpty(template.g, clone.getName())); } /* * (non-Javadoc) * * @see de.csdev.ebus.cfg.IEBusConfigurationReader#setEBusTypes(de.csdev.ebus.command.datatypes.EBusTypeRegistry) */ @Override public void setEBusTypes(EBusTypeRegistry ebusTypes) { registry = ebusTypes; } @Override public List<IEBusCommandCollection> loadConfigurationCollectionBundle(URL url) { List<IEBusCommandCollection> result = new ArrayList<IEBusCommandCollection>(); Gson gson = new Gson(); Type type = new TypeToken<Map<String, ?>>() { }.getType(); try { Map<String, ?> mapping = gson.fromJson(new InputStreamReader(url.openStream()), type); if (mapping.containsKey("files")) { @SuppressWarnings("unchecked") List<Map<String, String>> files = (List<Map<String, String>>) mapping.get("files"); for (Map<String, String> file : files) { URL fileUrl = new URL(url, file.get("url")); try { logger.debug("Load configuration from url {} ...", fileUrl); IEBusCommandCollection collection = loadConfigurationCollection(fileUrl); if (collection != null) { result.add(collection); } } catch (EBusConfigurationReaderException e) { logger.error(e.getMessage()); } catch (IOException e) { logger.error("error!", e); } } } } catch (JsonSyntaxException e) { logger.error("error!", e); } catch (JsonIOException e) { logger.error("error!", e); } catch (IOException e) { logger.error("error!", e); } return result; } @Override public void clear() { templateBlockRegistry.clear(); templateValueRegistry.clear(); } }