Java tutorial
// Copyright 2012 Google Inc. All Rights Reserved. // // 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.codenvy.dto.generator; import com.codenvy.dto.server.DtoFactoryVisitor; import com.codenvy.dto.shared.DTO; import com.google.common.hash.HashCode; import com.google.common.hash.Hashing; import org.reflections.Configuration; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; /** Simple source generator that takes in the packages list with interface definitions and generates client and server DTO impls. */ public class DtoGenerator { private static final String INVALID_PATH = "invalid path"; private static final String SERVER = "server"; private static final String CLIENT = "client"; /** Flag: location of the packages that contains dto interfaces. */ private String[] dtoPackages = null; /** Flag: Name of the generated java class file that contains the DTOs. */ private String genFileName = "DataObjects.java"; /** Flag: The type of impls to be generated, either CLIENT or SERVER. */ private String impl = CLIENT; /** Flag: A pattern we can use to search an absolute path and find the start of the package definition.") */ private String packageBase = "java."; public String[] getDtoPackages() { return dtoPackages; } public void setDtoPackages(String[] dtoPackages) { this.dtoPackages = new String[dtoPackages.length]; System.arraycopy(dtoPackages, 0, this.dtoPackages, 0, this.dtoPackages.length); } public String getGenFileName() { return genFileName; } public void setGenFileName(String genFileName) { this.genFileName = genFileName; } public String getImpl() { return impl; } public void setImpl(String impl) { this.impl = impl; } public String getPackageBase() { return packageBase; } public void setPackageBase(String packageBase) { this.packageBase = packageBase; } public static void main(String[] args) { DtoGenerator generator = new DtoGenerator(); for (String arg : args) { if (arg.startsWith("--dto_packages=")) { generator.setDtoPackages(arg.substring("--dto_packages=".length())); } else if (arg.startsWith("--gen_file_name=")) { generator.setGenFileName(arg.substring("--gen_file_name=".length())); } else if (arg.startsWith("--impl=")) { generator.setImpl(arg.substring("--impl=".length())); } else if (arg.startsWith("--package_base=")) { generator.setPackageBase(arg.substring("--package_base=".length())); } else { System.err.println("Unknown flag: " + arg); System.exit(1); } } generator.generate(); } private void setDtoPackages(String packagesParam) { setDtoPackages(packagesParam.split(",")); } public void generate() { Set<URL> urls = getClasspathForPackages(dtoPackages); String outputFilePath = genFileName; // Extract the name of the output file that will contain all the DTOs and its package. String myPackageBase = packageBase; if (!myPackageBase.endsWith("/")) { myPackageBase += "/"; } int packageStart = outputFilePath.lastIndexOf(myPackageBase) + myPackageBase.length(); int packageEnd = outputFilePath.lastIndexOf('/'); String fileName = outputFilePath.substring(packageEnd + 1); String className = fileName.substring(0, fileName.indexOf(".java")); String packageName = outputFilePath.substring(packageStart, packageEnd).replace('/', '.'); File outFile = new File(outputFilePath); try { StringBuilder sb = new StringBuilder(); for (String dtoPackage : dtoPackages) { if (sb.length() > 0) { sb.append(dtoPackage); } sb.append(dtoPackage); } DtoTemplate dtoTemplate = new DtoTemplate(packageName, className, getApiHash(sb.toString()), impl.equals(SERVER)); Reflections reflection = new Reflections( new ConfigurationBuilder().setUrls(urls).setScanners(new TypeAnnotationsScanner())); List<Class<?>> dtos = new ArrayList<>(reflection.getTypesAnnotatedWith(DTO.class)); // We sort alphabetically to ensure deterministic order of routing types. Collections.sort(dtos, new ClassesComparator()); for (Class<?> clazz : dtos) { dtoTemplate.addInterface(clazz); } reflection = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forClassLoader()) .setScanners(new TypeAnnotationsScanner())); List<Class<?>> dtosDependencies = new ArrayList<>(reflection.getTypesAnnotatedWith(DTO.class)); dtosDependencies.removeAll(dtos); reflection = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forClassLoader()) .setScanners(new SubTypesScanner())); for (Class<?> clazz : dtosDependencies) { for (Class impl : reflection.getSubTypesOf(clazz)) { if (!(impl.isInterface() || urls.contains(impl.getProtectionDomain().getCodeSource().getLocation()))) { if (DtoGenerator.this.impl.equals(CLIENT)) { if (isClientImpl(impl)) { dtoTemplate.addImplementation(clazz, impl); } } else if (!isClientImpl(impl)) { dtoTemplate.addImplementation(clazz, impl); } } } } // Emit the generated file. Files.createDirectories(outFile.toPath().getParent()); BufferedWriter writer = new BufferedWriter(new FileWriter(outFile)); writer.write(dtoTemplate.toString()); writer.close(); if (impl.equals(SERVER)) { // Create file in META-INF/services/ File outFile2 = new File( myPackageBase + "META-INF/services/" + DtoFactoryVisitor.class.getCanonicalName()); Files.createDirectories(outFile2.toPath().getParent()); BufferedWriter writer2 = new BufferedWriter(new FileWriter(outFile2)); writer2.write(packageName + "." + className); writer2.close(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private boolean isClientImpl(Class impl) { return impl.getName().contains(".client."); } private static String getApiHash(String packageName) throws IOException { byte[] fileBytes = packageName.getBytes(); HashCode hashCode = Hashing.sha1().hashBytes(fileBytes); return hashCode.toString(); } private static Set<URL> getClasspathForPackages(String[] packages) { Set<URL> urls = new HashSet<>(); for (String pack : packages) { urls.addAll(ClasspathHelper.forPackage(pack)); } return urls; } private static class ClassesComparator implements Comparator<Class> { @Override public int compare(Class o1, Class o2) { return o1.getName().compareTo(o2.getName()); } } }