All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hpe.adm.nga.sdk.generate.GenerateModels Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 Hewlett-Packard Enterprise Development Company, L.P.
 * 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 com.hpe.adm.nga.sdk.generate;

import com.hpe.adm.nga.sdk.Octane;
import com.hpe.adm.nga.sdk.authentication.SimpleClientAuthentication;
import com.hpe.adm.nga.sdk.metadata.EntityMetadata;
import com.hpe.adm.nga.sdk.metadata.FieldMetadata;
import com.hpe.adm.nga.sdk.metadata.Metadata;
import com.hpe.adm.nga.sdk.metadata.features.Feature;
import com.hpe.adm.nga.sdk.metadata.features.RestFeature;
import com.hpe.adm.nga.sdk.metadata.features.SubTypesOfFeature;
import com.hpe.adm.nga.sdk.model.EntityModel;
import com.hpe.adm.nga.sdk.model.ReferenceFieldModel;
import com.hpe.adm.nga.sdk.model.StringFieldModel;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 

The class that generates entities based on the metadata from the given ALM Octane server * This class generates models based on the {@link com.hpe.adm.nga.sdk.model.TypedEntityModel}, * entity lists based on {@link com.hpe.adm.nga.sdk.entities.TypedEntityList} and Lists & Phases objects * which represents those entities on the server and turns them into typed enums. *

*

* The user that calls the generation must have the workspace member of the given workspace. *

*

* UDFs are generated if they are part of the metadata for that workspace. That means that the generated * entities should be able to be reused over different workspaces within the same shared space. However * some business rules could cause different behaviour in different Workspaces. See the ALM Octane documentation * for more information *

*/ public class GenerateModels { private final Template template, interfaceTemplate, entityListTemplate, phasesTemplate, listsTemplate; private final File modelDirectory, entitiesDirectory, enumsDirectory; /** * Initialise the class with the output directory. This should normally be in a project that would be * imported into the main Java project * @param outputDirectory Where all the generated files will be placed */ public GenerateModels(final File outputDirectory) { final File packageDirectory = new File(outputDirectory, "/com/hpe/adm/nga/sdk"); modelDirectory = new File(packageDirectory, "model"); modelDirectory.mkdirs(); entitiesDirectory = new File(packageDirectory, "entities"); entitiesDirectory.mkdirs(); enumsDirectory = new File(packageDirectory, "enums"); enumsDirectory.mkdirs(); final VelocityEngine velocityEngine = new VelocityEngine(); velocityEngine.setProperty("resource.loader", "class"); velocityEngine.setProperty("class.resource.loader.description", "Velocity Classpath Resource Loader"); velocityEngine.setProperty("runtime.log.logsystem.log4j.logger", "root"); velocityEngine.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); velocityEngine.init(); template = velocityEngine.getTemplate("/EntityModel.vm"); interfaceTemplate = velocityEngine.getTemplate("/Entity.vm"); entityListTemplate = velocityEngine.getTemplate("/TypedEntityList.vm"); phasesTemplate = velocityEngine.getTemplate("/Phases.vm"); listsTemplate = velocityEngine.getTemplate("/Lists.vm"); } /** * Run the actual generation * @param clientId The client id * @param clientSecret The client secret * @param server The server including the protocol and port * @param sharedSpace The SS id * @param workSpace The WS id * @throws IOException A problem with the generation of the entities */ public void generate(String clientId, String clientSecret, String server, long sharedSpace, long workSpace) throws IOException { // work around for work_items_root final Octane octanePrivate = new Octane.Builder(new SimpleClientAuthentication(clientId, clientSecret, "HPE_REST_API_TECH_PREVIEW")).sharedSpace(sharedSpace).workSpace(workSpace).Server(server).build(); final EntityMetadata work_items_root = octanePrivate.metadata().entities("work_item_root").execute().iterator().next(); final Collection work_items_rootFields = octanePrivate.metadata().fields("work_item_root").execute(); octanePrivate.signOut(); final Octane octane = new Octane.Builder(new SimpleClientAuthentication(clientId, clientSecret)).sharedSpace(sharedSpace).workSpace(workSpace).Server(server).build(); final Metadata metadata = octane.metadata(); final Collection entityMetadata = metadata.entities().execute(); entityMetadata.add(work_items_root); final Map logicalNameToListsMap = generateLists(octane); final Set availablePhases = generatePhases(octane); for (EntityMetadata entityMetadatum : entityMetadata) { final String name = entityMetadatum.getName(); final String interfaceName = GeneratorHelper.camelCaseFieldName(name) + "Entity"; final Collection fieldMetadata = generateEntity(work_items_rootFields, metadata, entityMetadata, entityMetadatum, name, interfaceName, logicalNameToListsMap, availablePhases); generateInterface(entityMetadatum, name, interfaceName); generateEntityList(entityMetadatum, name, fieldMetadata); } } private Map generateLists(Octane octane) throws IOException { final Collection listNodes = octane.entityList("list_nodes").get().addFields("name", "list_root", "id", "logical_name").execute(); final Map> mappedListNodes = new HashMap<>(); final Map logicalNameToNameMap = new HashMap<>(); listNodes.forEach(listNode -> { final String rootId; final ReferenceFieldModel list_root = (ReferenceFieldModel) listNode.getValue("list_root"); final EntityModel list_rootValue = list_root.getValue(); final String name; if (list_rootValue != null) { rootId = list_rootValue.getId(); name = ((StringFieldModel) listNode.getValue("name")).getValue().replaceAll(" ", "_").replaceAll("^\\d", "_$0").replaceAll("\\W", "_").toUpperCase(); } else { rootId = listNode.getId(); name = GeneratorHelper.camelCaseFieldName(((StringFieldModel) listNode.getValue("name")).getValue().replaceAll("\\W", "_")); logicalNameToNameMap.put(((StringFieldModel) listNode.getValue("logical_name")).getValue(), name); } final List listHierarchy = mappedListNodes.computeIfAbsent(rootId, k -> new ArrayList<>()); final String[] listNodeInfo = {name, ((StringFieldModel) listNode.getValue("id")).getValue()}; if (list_rootValue == null) { listHierarchy.add(0, listNodeInfo); } else { listHierarchy.add(listNodeInfo); } }); final VelocityContext velocityContext = new VelocityContext(); velocityContext.put("listNodes", mappedListNodes); final FileWriter fileWriter = new FileWriter(new File(enumsDirectory, "Lists.java")); listsTemplate.merge(velocityContext, fileWriter); fileWriter.close(); return logicalNameToNameMap; } private Set generatePhases(Octane octane) throws IOException { final Map> phaseMap = new HashMap<>(); final Collection phases = octane.entityList("phases").get().addFields("id", "name", "entity").execute(); phases.forEach(phase -> { final Set phaseValueSet = new HashSet<>(); phaseValueSet.add(new String[]{phase.getId(), ((StringFieldModel) phase.getValue("name")).getValue() .replaceAll(" ", "_") .replaceAll("&", "N") .toUpperCase()}); phaseMap.merge(GeneratorHelper.camelCaseFieldName(((StringFieldModel) phase.getValue("entity")).getValue(), true), phaseValueSet, (existingValues, newValues) -> { existingValues.addAll(newValues); return existingValues; }); }); final VelocityContext velocityContext = new VelocityContext(); velocityContext.put("phaseMap", phaseMap); final FileWriter fileWriter = new FileWriter(new File(enumsDirectory, "Phases.java")); phasesTemplate.merge(velocityContext, fileWriter); fileWriter.close(); return phaseMap.keySet(); } private Collection generateEntity(Collection work_items_rootFields, Metadata metadata, Collection entityMetadata, EntityMetadata entityMetadatum, String name, String interfaceName, Map logicalNameToListsMap, Set availablePhases) throws IOException { final Collection fieldMetadata = name.equals("work_item_root") ? work_items_rootFields : metadata.fields(name).execute(); final TreeMap> collectedReferences = fieldMetadata.stream() .filter(FieldMetadata::isRequired) .collect(Collectors.toMap(FieldMetadata::getName, fieldMetadata1 -> { final List references = new ArrayList<>(); final String className = GeneratorHelper.camelCaseFieldName(entityMetadatum.getName()); if (fieldMetadata1.getName().equals("phase") && availablePhases.contains(className)) { references.add("com.hpe.adm.nga.sdk.enums.Phases." + className + "Phase"); } else if (fieldMetadata1.getFieldType() == FieldMetadata.FieldType.Reference) { if ((!entityMetadatum.getName().equals("list_node")) && (fieldMetadata1.getFieldTypedata().getTargets()[0].getType().equals("list_node"))) { final String listName = logicalNameToListsMap.get(fieldMetadata1.getFieldTypedata().getTargets()[0].logicalName()); references.add("com.hpe.adm.nga.sdk.enums.Lists." + listName); } else { final GeneratorHelper.ReferenceMetadata referenceMetadata = GeneratorHelper.getAllowedSuperTypesForReference(fieldMetadata1, entityMetadata); if (fieldMetadata1.getFieldTypedata().isMultiple()) { references.add(referenceMetadata.getReferenceClassForSignature()); } else { if (referenceMetadata.hasTypedReturn()) { references.addAll(referenceMetadata.getReferenceTypes() .stream() .map(type -> GeneratorHelper.camelCaseFieldName(type).concat("EntityModel")) .collect(Collectors.toSet())); } if (referenceMetadata.hasNonTypedReturn()) { references.add("EntityModel"); } } } } else { references.add(GeneratorHelper.getFieldTypeAsJava(fieldMetadata1.getFieldType())); } return references; }, (strings, strings2) -> { throw new IllegalStateException("problem merging map"); }, TreeMap::new)); final Set> requiredFields = new HashSet<>(); if (!collectedReferences.isEmpty()) { expandCollectedReferences(collectedReferences, new int[collectedReferences.size()], 0, requiredFields); } final VelocityContext velocityContext = new VelocityContext(); velocityContext.put("interfaceName", interfaceName); velocityContext.put("entityMetadata", entityMetadatum); velocityContext.put("fieldMetadata", fieldMetadata); velocityContext.put("logicalNameToListsMap", logicalNameToListsMap); velocityContext.put("entityMetadataCollection", entityMetadata); velocityContext.put("GeneratorHelper", GeneratorHelper.class); velocityContext.put("entityMetadataWrapper", GeneratorHelper.entityMetadataWrapper(entityMetadatum)); velocityContext.put("availablePhases", availablePhases); velocityContext.put("requiredFields", requiredFields); final FileWriter fileWriter = new FileWriter(new File(modelDirectory, GeneratorHelper.camelCaseFieldName(name) + "EntityModel.java")); template.merge(velocityContext, fileWriter); fileWriter.close(); return fieldMetadata; } private void expandCollectedReferences(final TreeMap> collectedReferences, final int[] positions, final int pointer, final Set> output) { final Object[] keyArray = collectedReferences.keySet().toArray(); final Object o = keyArray[pointer]; for (int i = 0; i < collectedReferences.get(o).size(); ++i) { if (pointer == positions.length - 1) { final List outputLine = new ArrayList<>(positions.length); for (int j = 0; j < positions.length; ++j) { outputLine.add(new String[]{(String) keyArray[j], collectedReferences.get(keyArray[j]).get(positions[j])}); } output.add(outputLine); } else { expandCollectedReferences(collectedReferences, positions, pointer + 1, output); } positions[pointer]++; } positions[pointer] = 0; } private void generateInterface(EntityMetadata entityMetadatum, String name, String interfaceName) throws IOException { // interface final VelocityContext interfaceVelocityContext = new VelocityContext(); final Optional subTypeOfFeature = entityMetadatum.features().stream().filter(feature -> feature instanceof SubTypesOfFeature).findAny(); interfaceVelocityContext.put("interfaceName", interfaceName); interfaceVelocityContext.put("superInterfaceName", (subTypeOfFeature.map(feature -> GeneratorHelper.camelCaseFieldName(((SubTypesOfFeature) feature).getType())).orElse("")) + "Entity"); final FileWriter interfaceFileWriter = new FileWriter(new File(modelDirectory, GeneratorHelper.camelCaseFieldName(name) + "Entity.java")); interfaceTemplate.merge(interfaceVelocityContext, interfaceFileWriter); interfaceFileWriter.close(); } private void generateEntityList(EntityMetadata entityMetadatum, String name, Collection fieldMetadata) throws IOException { // entityList final Optional hasRestFeature = entityMetadatum.features().stream() .filter(feature -> feature instanceof RestFeature) .findFirst(); // if not then something is wrong! if (hasRestFeature.isPresent()) { final RestFeature restFeature = (RestFeature) hasRestFeature.get(); final VelocityContext entityListVelocityContext = new VelocityContext(); entityListVelocityContext.put("helper", GeneratorHelper.class); entityListVelocityContext.put("type", GeneratorHelper.camelCaseFieldName(name)); entityListVelocityContext.put("url", restFeature.getUrl()); entityListVelocityContext.put("availableFields", fieldMetadata.stream().map(FieldMetadata::getName).collect(Collectors.toList())); entityListVelocityContext.put("sortableFields", fieldMetadata.stream().filter(FieldMetadata::isSortable).map(FieldMetadata::getName).collect(Collectors.toList())); final String[] restFeatureMethods = restFeature.getMethods(); for (String restFeatureMethod : restFeatureMethods) { switch (restFeatureMethod) { case "GET": entityListVelocityContext.put("hasGet", true); break; case "POST": entityListVelocityContext.put("hasCreate", true); break; case "PUT": entityListVelocityContext.put("hasUpdate", true); break; case "DELETE": entityListVelocityContext.put("hasDelete", true); break; } } final FileWriter entityListFileWriter = new FileWriter(new File(entitiesDirectory, GeneratorHelper.camelCaseFieldName(name) + "EntityList.java")); entityListTemplate.merge(entityListVelocityContext, entityListFileWriter); entityListFileWriter.close(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy