Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.olingo.ext.pojogen; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.GZIPOutputStream; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Triple; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Parameter; import org.apache.olingo.client.api.ODataClient; import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.edm.xml.XMLMetadata; import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.EdmSchema; import org.apache.olingo.commons.api.edm.EdmTerm; import org.apache.olingo.commons.api.format.ContentType; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.codehaus.plexus.util.FileUtils; public abstract class AbstractPOJOGenMojo extends AbstractMojo { /** * Generated files base root. */ @Parameter(property = "outputDirectory", required = true) protected String outputDirectory; /** * OData service root URL. */ @Parameter(property = "serviceRootURL", required = false) protected String serviceRootURL; /** * Local file from which Edm information can be loaded. */ @Parameter(property = "localEdm", required = false) protected String localEdm; /** * Base package. */ @Parameter(property = "basePackage", required = false) protected String basePackage; protected final Set<String> namespaces = new HashSet<String>(); protected static String TOOL_DIR = "ojc-plugin"; protected AbstractUtility utility; protected abstract String getVersion(); protected File mkdir(final String path) { final File dir = new File(outputDirectory + File.separator + TOOL_DIR + File.separator + path); if (dir.exists()) { if (!dir.isDirectory()) { throw new IllegalArgumentException("Invalid path '" + path + "': it is not a directory"); } } else { dir.mkdirs(); } return dir; } protected File mkPkgDir(final String path) { return StringUtils.isBlank(basePackage) ? mkdir(path) : mkdir(basePackage.replace('.', File.separatorChar) + File.separator + path); } protected void writeFile(final String name, final File path, final VelocityContext ctx, final Template template, final boolean append) throws MojoExecutionException { if (!path.exists()) { throw new IllegalArgumentException("Invalid base path '" + path.getAbsolutePath() + "'"); } FileWriter writer = null; try { final File toBeWritten = new File(path, name); if (!append && toBeWritten.exists()) { throw new IllegalStateException("File '" + toBeWritten.getAbsolutePath() + "' already exists"); } writer = new FileWriter(toBeWritten, append); template.merge(ctx, writer); } catch (IOException e) { throw new MojoExecutionException("Error creating file '" + name + "'", e); } finally { IOUtils.closeQuietly(writer); } } protected VelocityContext newContext() { final VelocityContext ctx = new VelocityContext(); ctx.put("utility", getUtility()); ctx.put("basePackage", basePackage); ctx.put("schemaName", getUtility().getSchemaName()); ctx.put("namespace", getUtility().getNamespace()); ctx.put("namespaces", namespaces); ctx.put("odataVersion", getVersion()); return ctx; } protected void parseObj(final File base, final String pkg, final String name, final String out) throws MojoExecutionException { parseObj(base, false, pkg, name, out, Collections.<String, Object>emptyMap()); } protected void parseObj(final File base, final String pkg, final String name, final String out, final Map<String, Object> objs) throws MojoExecutionException { parseObj(base, false, pkg, name, out, objs); } protected void parseObj(final File base, final boolean append, final String pkg, final String name, final String out, final Map<String, Object> objs) throws MojoExecutionException { final VelocityContext ctx = newContext(); ctx.put("package", pkg); if (objs != null) { for (Map.Entry<String, Object> obj : objs.entrySet()) { if (StringUtils.isNotBlank(obj.getKey()) && obj.getValue() != null) { ctx.put(obj.getKey(), obj.getValue()); } } } final Template template = Velocity.getTemplate(name + ".vm"); writeFile(out, base, ctx, template, append); } protected abstract void createUtility(Edm edm, EdmSchema schema, String basePackage); protected abstract AbstractUtility getUtility(); protected abstract ODataClient getClient(); private Triple<XMLMetadata, String, Edm> getMetadata() throws FileNotFoundException { if (StringUtils.isEmpty(serviceRootURL) && StringUtils.isEmpty(localEdm)) { throw new IllegalArgumentException("Must provide either serviceRootURL or localEdm"); } if (StringUtils.isNotEmpty(serviceRootURL) && StringUtils.isNotEmpty(localEdm)) { throw new IllegalArgumentException("Must provide either serviceRootURL or localEdm, not both"); } XMLMetadata metadata = null; String metadataETag = null; Edm edm = null; if (StringUtils.isNotEmpty(serviceRootURL)) { final EdmMetadataRequest req = getClient().getRetrieveRequestFactory() .getMetadataRequest(serviceRootURL); metadata = req.getXMLMetadata(); final ODataRetrieveResponse<Edm> res = req.execute(); metadataETag = res.getETag(); edm = res.getBody(); } else if (StringUtils.isNotEmpty(localEdm)) { final FileInputStream fis = new FileInputStream(FileUtils.getFile(localEdm)); try { metadata = getClient().getDeserializer(ContentType.APPLICATION_XML).toMetadata(fis); edm = getClient().getReader().readMetadata(metadata.getSchemaByNsOrAlias()); } finally { IOUtils.closeQuietly(fis); } } if (metadata == null || edm == null) { throw new IllegalStateException("Metadata not found"); } return new ImmutableTriple<XMLMetadata, String, Edm>(metadata, metadataETag, edm); } @Override public void execute() throws MojoExecutionException, MojoFailureException { if (new File(outputDirectory + File.separator + TOOL_DIR).exists()) { getLog().info("Nothing to do because " + TOOL_DIR + " directory already exists. Clean to update."); return; } Velocity.addProperty(Velocity.RESOURCE_LOADER, "class"); Velocity.addProperty("class.resource.loader.class", ClasspathResourceLoader.class.getName()); try { final Triple<XMLMetadata, String, Edm> metadata = getMetadata(); for (EdmSchema schema : metadata.getRight().getSchemas()) { namespaces.add(schema.getNamespace().toLowerCase()); } final Map<String, String> entityTypeNames = new HashMap<String, String>(); final Map<String, String> complexTypeNames = new HashMap<String, String>(); final Map<String, String> enumTypeNames = new HashMap<String, String>(); final Map<String, String> termNames = new HashMap<String, String>(); final Map<String, Object> objs = new HashMap<String, Object>(); for (EdmSchema schema : metadata.getRight().getSchemas()) { createUtility(metadata.getRight(), schema, basePackage); // write package-info for the base package final String schemaPath = utility.getNamespace().toLowerCase().replace('.', File.separatorChar); final File base = mkPkgDir(schemaPath); final String pkg = StringUtils.isBlank(basePackage) ? utility.getNamespace().toLowerCase() : basePackage + "." + utility.getNamespace().toLowerCase(); parseObj(base, pkg, "package-info", "package-info.java"); // write package-info for types package final File typesBaseDir = mkPkgDir(schemaPath + "/types"); final String typesPkg = pkg + ".types"; parseObj(typesBaseDir, typesPkg, "package-info", "package-info.java"); for (EdmTerm term : schema.getTerms()) { final String className = utility.capitalize(term.getName()); termNames.put(term.getFullQualifiedName().toString(), typesPkg + "." + className); objs.clear(); objs.put("term", term); parseObj(typesBaseDir, typesPkg, "term", className + ".java", objs); } for (EdmEnumType enumType : schema.getEnumTypes()) { final String className = utility.capitalize(enumType.getName()); enumTypeNames.put(enumType.getFullQualifiedName().toString(), typesPkg + "." + className); objs.clear(); objs.put("enumType", enumType); parseObj(typesBaseDir, typesPkg, "enumType", className + ".java", objs); } final List<EdmComplexType> complexes = new ArrayList<EdmComplexType>(); for (EdmComplexType complex : schema.getComplexTypes()) { complexes.add(complex); final String className = utility.capitalize(complex.getName()); complexTypeNames.put(complex.getFullQualifiedName().toString(), typesPkg + "." + className); objs.clear(); objs.put("complexType", complex); parseObj(typesBaseDir, typesPkg, "complexType", className + ".java", objs); parseObj(typesBaseDir, typesPkg, "complexTypeComposableInvoker", className + "ComposableInvoker.java", objs); parseObj(typesBaseDir, typesPkg, "complexCollection", className + "Collection.java", objs); parseObj(typesBaseDir, typesPkg, "complexCollectionComposableInvoker", className + "CollectionComposableInvoker.java", objs); } for (EdmEntityType entity : schema.getEntityTypes()) { final String className = utility.capitalize(entity.getName()); entityTypeNames.put(entity.getFullQualifiedName().toString(), typesPkg + "." + className); objs.clear(); objs.put("entityType", entity); final Map<String, String> keys; EdmEntityType baseType = null; if (entity.getBaseType() == null) { keys = getUtility().getEntityKeyType(entity); } else { baseType = entity.getBaseType(); objs.put("baseType", getUtility().getJavaType(baseType.getFullQualifiedName().toString())); while (baseType.getBaseType() != null) { baseType = baseType.getBaseType(); } keys = getUtility().getEntityKeyType(baseType); } if (keys.size() > 1) { // create compound key class final String keyClassName = utility .capitalize(baseType == null ? entity.getName() : baseType.getName()) + "Key"; objs.put("keyRef", keyClassName); if (entity.getBaseType() == null) { objs.put("keys", keys); parseObj(typesBaseDir, typesPkg, "entityTypeKey", keyClassName + ".java", objs); } } parseObj(typesBaseDir, typesPkg, "entityType", className + ".java", objs); parseObj(typesBaseDir, typesPkg, "entityComposableInvoker", className + "ComposableInvoker.java", objs); parseObj(typesBaseDir, typesPkg, "entityCollection", className + "Collection.java", objs); parseObj(typesBaseDir, typesPkg, "entityCollectionComposableInvoker", className + "CollectionComposableInvoker.java", objs); } // write container and top entity sets into the base package EdmEntityContainer container = schema.getEntityContainer(); if (container != null) { objs.clear(); objs.put("container", container); objs.put("namespace", schema.getNamespace()); objs.put("complexes", complexes); parseObj(base, pkg, "container", utility.capitalize(container.getName()) + ".java", objs); for (EdmEntitySet entitySet : container.getEntitySets()) { objs.clear(); objs.put("entitySet", entitySet); objs.put("container", container); parseObj(base, pkg, "entitySet", utility.capitalize(entitySet.getName()) + ".java", objs); } } } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final GZIPOutputStream gzos = new GZIPOutputStream(baos); final ObjectOutputStream oos = new ObjectOutputStream(gzos); try { oos.writeObject(metadata.getLeft()); } finally { oos.close(); gzos.close(); baos.close(); } objs.clear(); objs.put("metadata", new String(Base64.encodeBase64(baos.toByteArray()), "UTF-8")); objs.put("metadataETag", metadata.getMiddle()); objs.put("entityTypes", entityTypeNames); objs.put("complexTypes", complexTypeNames); objs.put("enumTypes", enumTypeNames); objs.put("terms", termNames); final String actualBP = StringUtils.isBlank(basePackage) ? StringUtils.EMPTY : basePackage; parseObj(mkdir(actualBP.replace('.', File.separatorChar)), actualBP, "service", "Service.java", objs); } catch (Exception t) { getLog().error(t); throw (t instanceof MojoExecutionException) ? (MojoExecutionException) t : new MojoExecutionException("While executin mojo", t); } } }