Java tutorial
/** * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.md file. */ package org.mule.modules.servicesource.metadata; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.mule.common.metadata.DefaultDefinedMapMetaDataModel; import org.mule.common.metadata.DefaultListMetaDataModel; import org.mule.common.metadata.DefaultMetaData; import org.mule.common.metadata.DefaultParameterizedMapMetaDataModel; import org.mule.common.metadata.DefaultSimpleMetaDataModel; import org.mule.common.metadata.MetaData; import org.mule.common.metadata.MetaDataModel; import org.mule.common.metadata.datatype.DataType; import org.mule.modules.servicesource.ServiceSourceCollection; import org.mule.modules.servicesource.model.Amount; import org.mule.modules.servicesource.model.PropertyDescriptor; import com.google.gson.annotations.SerializedName; /** * * @author mariano.gonzalez@mulesoft.com * */ public class MetadataExtractor { private Map<Class<?>, Map<String, MetaDataModel>> pojoModelCache = new HashMap<Class<?>, Map<String, MetaDataModel>>(); public MetaData extractStaticMetadata(ServiceSourceCollection collection) { return new DefaultMetaData(new DefaultDefinedMapMetaDataModel(describeStatic(collection))); } public MetaData extractMetadata(Map<String, Object> metadata, ServiceSourceCollection collection) { Map<String, MetaDataModel> model = describeStatic(collection); // System.out.println(metadata); this.describeExtensions(metadata, model); this.describeRelations(metadata, model); return new DefaultMetaData(new DefaultDefinedMapMetaDataModel(model)); } @SuppressWarnings("unchecked") private void describeRelations(Map<String, Object> elements, Map<String, MetaDataModel> model) { List<Map<String, Object>> relationships = (List<Map<String, Object>>) elements.get("relations"); List<Map<String, Object>> subTypes = (List<Map<String, Object>>) elements.get("subTypes"); List<Map<String, Object>> subTypesRelationships = new ArrayList<Map<String, Object>>(); if (subTypes != null) { for (Map<String, Object> subType : subTypes) { if (subType.get("relations") != null) { subTypesRelationships.addAll((List<Map<String, Object>>) subType.get("relations")); } } } if (relationships == null && subTypesRelationships.isEmpty()) { return; } Map<String, MetaDataModel> relations = this.newModelMap(); if (relationships != null) { createRelations(relationships, relations); } if (!subTypesRelationships.isEmpty()) { createRelations(subTypesRelationships, relations); } if (!relations.isEmpty()) { model.put("relations", new DefaultDefinedMapMetaDataModel(relations)); } } private void createRelations(List<Map<String, Object>> relationships, Map<String, MetaDataModel> relations) { for (Map<String, Object> element : relationships) { String cardinality = (String) element.get("cardinality"); if (StringUtils.isBlank(cardinality)) { throw new IllegalArgumentException("relation is missing cardinality element"); } MetaDataModel keyModel = new DefaultSimpleMetaDataModel(DataType.STRING); Map<String, MetaDataModel> relationModel = this.newModelMap(); relationModel.put("key", keyModel); String target = (String) element.get("target"); if (target.contains("/")) { target = target.substring(0, target.indexOf("/")); } relations.put(String.format("%s (%s)", element.get("name"), target), new DefaultDefinedMapMetaDataModel(relationModel)); this.describeRelations(element, relationModel); } } @SuppressWarnings("unchecked") private void describeExtensions(Map<String, Object> metadata, Map<String, MetaDataModel> model) { Map<String, MetaDataModel> master = this.newModelMap(); Map<String, MetaDataModel> tenant = this.newModelMap(); for (Map<String, Object> ext : (List<Map<String, Object>>) metadata.get("properties")) { if ("true".equals(ext.get("extension"))) { MetaDataModel extensionModel = this.parseElementByType(ext); MetaDataModel meta = "true".equals(ext.get("isArray")) ? new DefaultListMetaDataModel(extensionModel) : extensionModel; ("true".equals(ext.get("master")) ? master : tenant).put((String) ext.get("name"), meta); } } Map<String, MetaDataModel> modelExtensions = this.newModelMap(); modelExtensions.put("master", new DefaultDefinedMapMetaDataModel(master)); modelExtensions.put("tenant", new DefaultDefinedMapMetaDataModel(tenant)); model.put("extensions", new DefaultDefinedMapMetaDataModel(modelExtensions)); } private Map<String, MetaDataModel> describeStatic(ServiceSourceCollection collection) { Map<String, MetaDataModel> model = this.newModelMap(); describeModel(model, collection.getType(), null); return model; } private MetaDataModel parseElementByType(Map<String, Object> extension) { return this.parseElement((String) extension.get("type")); } private MetaDataModel parseElement(String type) { if ("string".equals(type)) { return new DefaultSimpleMetaDataModel(DataType.STRING); } else if ("number".equals(type)) { return new DefaultSimpleMetaDataModel(DataType.NUMBER); } else if ("lookup".equals(type)) { return describeModel(this.newModelMap(), PropertyDescriptor.class, null); } else if ("core.currency".equals(type)) { return describeModel(this.newModelMap(), Amount.class, null); } else if ("boolean".equals(type)) { return new DefaultSimpleMetaDataModel(DataType.BOOLEAN); } else if ("date".equals(type)) { return new DefaultSimpleMetaDataModel(DataType.DATE_TIME); } else { ServiceSourceCollection collection = ServiceSourceCollection.getByEntityName(type); if (collection != null) { return new DefaultDefinedMapMetaDataModel(describeStatic(collection)); } } return null; } public MetaDataModel describeModel(Map<String, MetaDataModel> model, Class<?> type, Field field) { DataType dataType = getDataType(type); MetaDataModel result = null; if (DataType.POJO.equals(dataType)) { Map<String, MetaDataModel> cachedModel = this.pojoModelCache.get(type); if (cachedModel != null) { model = cachedModel; } else { this.pojoModelCache.put(type, model); for (Field pojoField : getFields(type)) { if (pojoField.getType() == null || Modifier.isStatic(pojoField.getModifiers())) { continue; // this is a native type } String name = pojoField.getName(); if ("extensions".equals(name) || "relationships".equals(name)) { continue; } else { SerializedName annotation = pojoField.getAnnotation(SerializedName.class); name = annotation != null ? annotation.value() : pojoField.getName(); } model.put(name, describeModel(newModelMap(), pojoField.getType(), pojoField)); } } result = new DefaultDefinedMapMetaDataModel(model); } else if (DataType.MAP.equals(dataType)) { result = new DefaultParameterizedMapMetaDataModel(new DefaultSimpleMetaDataModel(DataType.STRING), new DefaultSimpleMetaDataModel(DataType.STRING)); model.put(field.getName(), result); } else if (DataType.LIST.equals(dataType)) { Class<?> listType = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; result = new DefaultListMetaDataModel(describeModel(newModelMap(), listType, field)); model.put(field.getName(), result); } else { result = new DefaultSimpleMetaDataModel(dataType); model.put(field.getName(), result); } return result; } private DataType getDataType(Class<?> type) { if (String.class.equals(type)) { return DataType.STRING; } else if (Integer.class.equals(type) || Long.class.equals(type) || Double.class.equals(type)) { return DataType.NUMBER; } else if (Boolean.class.equals(type)) { return DataType.BOOLEAN; } else if (Map.class.isAssignableFrom(type)) { return DataType.MAP; } else if (List.class.isAssignableFrom(type)) { return DataType.LIST; } else { return DataType.POJO; } } private Collection<Field> getFields(Class<?> type) { Collection<Field> fields = new ArrayList<Field>(); while (!type.equals(Object.class)) { fields.addAll(Arrays.asList(type.getDeclaredFields())); type = type.getSuperclass(); } return fields; } private Map<String, MetaDataModel> newModelMap() { return new HashMap<String, MetaDataModel>(); } }