/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsplugin.sourcegen; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Collection; import java.util.EventListener; import java.util.EventObject; import java.util.Iterator; import java.util.StringTokenizer; import java.util.Vector; import org.eclipse.persistence.tools.workbench.framework.context.ApplicationContext; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWMappingDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProject; import org.eclipse.persistence.internal.codegen.ClassDefinition; import org.eclipse.persistence.internal.codegen.CodeGenerator; public final class SourceCodeGenerator { private ApplicationContext context; private MWProject project; private Collection descriptors; private File sourceRootDirectory; private boolean overwriteFiles; private boolean continueGenerating; private boolean anyFileWritten; private Collection fileAlreadyExistsListeners; private Collection continuableExceptionListeners; // **************** member types ****************************************** public class ContinuableExceptionEvent extends EventObject { private Exception exception; protected ContinuableExceptionEvent(Object source, Exception exception) { super(source); this.exception = exception; } public Exception getException() { return this.exception; } } public interface ContinuableExceptionListener extends EventListener { boolean continueOnException(ContinuableExceptionEvent cee); } public class FileAlreadyExistsEvent extends EventObject { private File file; protected FileAlreadyExistsEvent(Object source, File file) { super(source); this.file = file; } public File getFile() { return this.file; } } public interface FileAlreadyExistsListener extends EventListener { boolean fileAlreadyExists(MWProject project, FileAlreadyExistsEvent event); } // **************** constructor ******************************************* public SourceCodeGenerator(ApplicationContext context) { this.context = context; this.fileAlreadyExistsListeners = new Vector(); this.continuableExceptionListeners = new Vector(); this.continueGenerating = true; } // **************** accessors ********************************************* private ApplicationContext getApplicationContext() { return this.context; } public boolean shouldOverwriteFiles() { return this.overwriteFiles; } public void setOverwriteFiles(boolean overwriteFiles) { this.overwriteFiles = overwriteFiles; } // **************** behavior ********************************************* public void generateSourceCode(MWProject project, Collection descriptors) { this.generateSourceCode(project, descriptors, null); } public void generateSourceCode(MWProject project, Collection descriptors, File sourceRootDirectory) { this.project = project; this.descriptors = descriptors; this.sourceRootDirectory = sourceRootDirectory; if (!this.overwriteFiles) { checkForExistingFiles(); } for (Iterator it = descriptors.iterator(); it.hasNext();) generateSourceCode((MWDescriptor) it.next()); } private void generateSourceCode(MWDescriptor descriptor) { writeClassDefinition(new BasicDescriptorClassCodeGenPolicy(descriptor, getApplicationContext()).classDefinition()); } public void checkForExistingFiles() { File existingFile = null; for (Iterator iter = this.descriptors.iterator(); iter.hasNext(); ) { MWDescriptor descriptor = (MWDescriptor) iter.next(); existingFile = doesFileExist(descriptor); if (existingFile != null) { break; } } if (existingFile != null) { fireFileAlreadyExistsEvent(existingFile); } } private File doesFileExist(MWDescriptor descriptor) { return doesFileExist(new BasicDescriptorClassCodeGenPolicy(descriptor, getApplicationContext()).classDefinition()); } private File doesFileExist(ClassDefinition classDef) { if (! this.continueGenerating) return null; // could be null in the case of a core type if (classDef == null) return null; File sourceRootDirectory = this.sourceRootDirectory; if (sourceRootDirectory == null) sourceRootDirectory = this.project.absoluteModelSourceDirectory(); String writeDirectory = buildDirectory(classDef.getPackageName(), sourceRootDirectory); File javaFile = new File(writeDirectory, classDef.getName() + ".java"); if (javaFile.exists()) return javaFile; return null; } public void writeClassDefinition(ClassDefinition classDef) { if (! this.continueGenerating) return; // could be null in the case of a core type if (classDef == null) return; File sourceRootDirectory = this.sourceRootDirectory; if (sourceRootDirectory == null) sourceRootDirectory = this.project.absoluteModelSourceDirectory(); String writeDirectory = buildDirectory(classDef.getPackageName(), sourceRootDirectory); File javaFile = new File(writeDirectory, classDef.getName() + ".java"); CodeGenerator codeGenerator = new CodeGenerator(); try { FileOutputStream stream = new FileOutputStream(javaFile); codeGenerator.setOutput(new OutputStreamWriter(stream, "utf-8")); } catch (IOException ioe) { fireContinuableExceptionEvent(ioe); return; } classDef.write(codeGenerator); this.anyFileWritten = true; try { codeGenerator.getOutput().flush(); codeGenerator.getOutput().close(); } catch (IOException ioe) { fireContinuableExceptionEvent(ioe); return; } } public void removeFileAlreadyExistsListener(FileAlreadyExistsListener listener) { this.fileAlreadyExistsListeners.remove(listener); } private String buildDirectory(String packageName, File rootDirectory) { StringTokenizer tokenizer = new StringTokenizer(packageName, "."); File currentDirectory = rootDirectory; currentDirectory.mkdir(); while (tokenizer.hasMoreTokens()) { currentDirectory = new File(currentDirectory.getPath() + File.separator + tokenizer.nextToken()); currentDirectory.mkdir(); } return currentDirectory.getPath(); } // **************** continuable exception stuff *************************** public void addContinuableExceptionListener(ContinuableExceptionListener listener) { this.continuableExceptionListeners.add(listener); } private void fireContinuableExceptionEvent(Exception exception) { for (Iterator listeners = this.continuableExceptionListeners.iterator(); listeners.hasNext();) this.continueGenerating &= ((ContinuableExceptionListener) listeners.next()).continueOnException(new ContinuableExceptionEvent(this, exception)); } // **************** file already exists stuff ***************************** public void addFileAlreadyExistsListener(FileAlreadyExistsListener listener) { this.fileAlreadyExistsListeners.add(listener); } private void fireFileAlreadyExistsEvent(File file) { for (Iterator listeners = this.fileAlreadyExistsListeners.iterator(); listeners.hasNext();) this.continueGenerating &= ((FileAlreadyExistsListener) listeners.next()).fileAlreadyExists(this.project, new FileAlreadyExistsEvent(this, file)); } public boolean isAnyFileWritten() { return this.anyFileWritten; } }