/*******************************************************************************
* 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.mappingsio.legacy;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import java.util.prefs.Preferences;
import org.eclipse.persistence.tools.workbench.mappingsio.FileNotFoundListener;
import org.eclipse.persistence.tools.workbench.mappingsio.LegacyProjectReadCallback;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProjectSubFileComponentContainer;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProject;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.DefaultSPIManager;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.SPIManager;
import org.eclipse.persistence.tools.workbench.utility.ClassTools;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.io.FileTools;
import org.eclipse.persistence.tools.workbench.utility.string.StringTools;
/**
* A new instance of this class is created for each project read:
* MWProject project = new ProjectReader(ioManager, file, preferences, listener).read()
*/
class Project60Reader {
/** The I/O manager that created this reader. */
private Project60IOManager ioManager;
/** The project file to be read. */
private File file;
/** The user preferences used to configure the SPI manager. */
private Preferences preferences;
/** A listener that will be notified whenever an "expected" file is missing. */
private FileNotFoundListener listener;
// ********** constructors **********
Project60Reader(Project60IOManager ioManager, File file, Preferences preferences, FileNotFoundListener listener) {
super();
this.ioManager = ioManager;
this.file = file;
this.preferences = preferences;
this.listener = listener;
}
// ********** public stuff **********
/**
* Read a project from the file, using the appropriate "schema".
*/
MWProject read() {
return this.readProject();
}
public String toString() {
return StringTools.buildToStringFor(this, this.file);
}
// ********** internal stuff **********
/**
* read a normal (non-legacy) project from the file and return it
*/
private MWProject readProject() {
// first read in the project, but none of its components (classes, metadata, descriptors)
MWProject project;
try {
project = (MWProject) this.readObject(this.file);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
// "inject" the SPIManager once we have the base project
this.injectSPIManager(project, new DefaultSPIManager(this.preferences, project.getName()));
// then use the names stored throughout the project to read up its components
SubComponentReader[] subComponentReaders = this.buildSubComponentReaders(project);
for (int i = 0; i < subComponentReaders.length; i++) {
subComponentReaders[i].read();
}
// now trigger all the handles to resolve etc.
project.postProjectBuild();
return project;
}
/**
* build readers for all the project's sub-components that are
* read in separately: classes, tables, descriptors
*/
private SubComponentReader[] buildSubComponentReaders(MWProject project) {
return new SubComponentReader[] {
new SubComponentReader(project.getClassRepository()),
new SubComponentReader(project.getMetaDataSubComponentContainer()),
new SubComponentReader(project.getDescriptorRepository()),
};
}
/**
* Use TopLink to unmarshal an object from the specified XML file.
* Let the exceptions through so we can swallow the FileNotFoundException
* when reading sub-components.
*/
Object readObject(File xmlFile) throws IOException {
InputStream stream = null;
Object object = null;
try {
stream = new BufferedInputStream(new FileInputStream(xmlFile));
object = this.ioManager.getUnmarshaller().unmarshal(stream);
} finally {
if (stream != null) {
stream.close();
}
}
return object;
}
/**
* return the base directory for all the project files;
* the project file is in this directory, while all the other
* files are in subdirectories of this directory
*/
File baseDirectory() {
return this.file.getParentFile();
}
String defaultFileNameExtension() {
return this.ioManager.defaultFileNameExtension();
}
String subDirectoryNameFor(Object container) {
return this.ioManager.subDirectoryNameFor(container);
}
void fireFileNotFound(File missingFile) {
this.ioManager.fireFileNotFound(this.listener, missingFile);
}
private void injectSPIManager(MWProject project, SPIManager spiManager) {
ClassTools.invokeMethod(project, "setSPIManagerForIOManager", SPIManager.class, spiManager);
}
// ********** inner classes **********
/**
* Delegate sub-component-related behavior to this class.
*/
private class SubComponentReader {
/** the container that will hold the sub-components once they are read */
private ProjectSubFileComponentContainer container;
SubComponentReader(ProjectSubFileComponentContainer container) {
this.container = container;
}
void read() {
String ext = Project60Reader.this.defaultFileNameExtension();
// build the sub-directory that holds the sub-components
String subDirectoryName = Project60Reader.this.subDirectoryNameFor(this.container);
File subDirectory = new File(this.baseDirectory(), subDirectoryName);
// the sub-component names are set by TopLink when the project is read;
// and reset by ProjectWriter when the project is saved
Collection names = CollectionTools.set(this.container.originalProjectSubFileComponentNames());
// now use the sub-component names to read in the actual sub-components
Collection subComponents = new Vector(names.size());
for (Iterator stream = names.iterator(); stream.hasNext(); ) {
String name = (String) stream.next();
String fileName = FileTools.FILE_NAME_ENCODER.encode(name);
File subFile = new File(subDirectory, fileName + ext);
MWModel subComponent = (MWModel) this.readObject(subFile);
if (subComponent == null) {
Project60Reader.this.fireFileNotFound(subFile);
stream.remove(); // keep the list of names in synch with the files
} else {
subComponent.setParent((org.eclipse.persistence.tools.workbench.utility.node.Node) this.container);
subComponents.add(subComponent);
}
}
// and finally, put the sub-components into the container
this.container.setProjectSubFileComponents(subComponents);
}
private File baseDirectory() {
return Project60Reader.this.baseDirectory();
}
private Object readObject(File xmlFile) {
try {
return Project60Reader.this.readObject(xmlFile);
} catch (FileNotFoundException ex) {
return null;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}