blob: 0413d8f066b02596bace0bf7fc7ef4c0cbf81ccd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.core.internal.context.persistence;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jpt.common.core.utility.TextRange;
import org.eclipse.jpt.common.utility.internal.StringTools;
import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable;
import org.eclipse.jpt.common.utility.internal.iterables.SingleElementIterable;
import org.eclipse.jpt.jpa.core.JpaFile;
import org.eclipse.jpt.jpa.core.JpaStructureNode;
import org.eclipse.jpt.jpa.core.JptJpaCorePlugin;
import org.eclipse.jpt.jpa.core.context.PersistentType;
import org.eclipse.jpt.jpa.core.context.java.JarFile;
import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType;
import org.eclipse.jpt.jpa.core.context.persistence.JarFileRef;
import org.eclipse.jpt.jpa.core.context.persistence.PersistenceStructureNodes;
import org.eclipse.jpt.jpa.core.context.persistence.PersistenceUnit;
import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages;
import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages;
import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePackageFragmentRoot;
import org.eclipse.jpt.jpa.core.resource.persistence.XmlJarFileRef;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.resources.IVirtualFile;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
/**
* <code>persistence.xml</code> file
* <br>
* <code>jar-file</code> element
*/
public abstract class AbstractJarFileRef
extends AbstractPersistenceXmlContextNode
implements JarFileRef
{
protected final XmlJarFileRef xmlJarFileRef;
protected String fileName;
/**
* the jar file corresponding to the ref's file name;
* this can be null if the name is invalid
*/
protected JarFile jarFile;
// ********** construction/initialization **********
public AbstractJarFileRef(PersistenceUnit parent, XmlJarFileRef xmlJarFileRef) {
super(parent);
this.xmlJarFileRef = xmlJarFileRef;
this.fileName = xmlJarFileRef.getFileName();
this.jarFile = this.buildJarFile();
}
// ********** synchronize/update **********
@Override
public void synchronizeWithResourceModel() {
super.synchronizeWithResourceModel();
this.setFileName_(this.xmlJarFileRef.getFileName());
this.syncJarFile();
}
@Override
public void update() {
super.update();
this.updateJarFile();
}
// ********** JpaStructureNode implementation **********
public String getId() {
return PersistenceStructureNodes.JAR_FILE_REF_ID;
}
public JpaStructureNode getStructureNode(int textOffset) {
return this;
}
public TextRange getSelectionTextRange() {
return (this.xmlJarFileRef == null) ? null : this.xmlJarFileRef.getSelectionTextRange();
}
public void dispose() {
if (this.jarFile != null) {
this.jarFile.dispose();
}
}
// ********** file name **********
public String getFileName() {
return this.fileName;
}
public void setFileName(String fileName) {
this.setFileName_(fileName);
this.xmlJarFileRef.setFileName(fileName);
}
/**
* We clear out {@link #jarFile} here because we cannot compare its file
* name to the ref's file name, since it may have been munged (see
* {@link #resolveJavaResourcePackageFragmentRoot_()}).
*/
protected void setFileName_(String fileName) {
String old = this.fileName;
this.fileName = fileName;
if (this.firePropertyChanged(FILE_NAME_PROPERTY, old, fileName)) {
// clear out the jar file here, it will be rebuilt during "update"
if (this.jarFile != null) {
this.jarFile.dispose();
this.setJarFile(null);
}
}
}
// ********** jar file **********
public JarFile getJarFile() {
return this.jarFile;
}
protected void setJarFile(JarFile jarFile) {
JarFile old = this.jarFile;
this.jarFile = jarFile;
this.firePropertyChanged(JAR_FILE_PROPERTY, old, jarFile);
}
protected JarFile buildJarFile() {
JavaResourcePackageFragmentRoot jrpfr = this.resolveJavaResourcePackageFragmentRoot();
return (jrpfr == null) ? null : this.buildJarFile(jrpfr);
}
/**
* If the file name changes during <em>sync</em>, the jar file will be
* cleared out in {@link #setFileName_(String)}. If we get here and the jar
* file is still present, we can <code>sync</code> it. Of course, it might
* still be obsolete if other things have changed....
*
* @see #updateJarFile()
*/
protected void syncJarFile() {
if (this.jarFile != null) {
this.jarFile.synchronizeWithResourceModel();
}
}
/**
* @see #syncJarFile()
*/
protected void updateJarFile() {
JavaResourcePackageFragmentRoot jrpfr = this.resolveJavaResourcePackageFragmentRoot();
if (jrpfr == null) {
if (this.jarFile != null) {
this.jarFile.dispose();
this.setJarFile(null);
}
} else {
if (this.jarFile == null) {
this.setJarFile(this.buildJarFile(jrpfr));
} else {
if (this.jarFile.getJarResourcePackageFragmentRoot() == jrpfr) {
this.jarFile.update();
} else {
this.jarFile.dispose();
this.setJarFile(this.buildJarFile(jrpfr));
}
}
}
}
protected JavaResourcePackageFragmentRoot resolveJavaResourcePackageFragmentRoot() {
return StringTools.stringIsEmpty(this.fileName) ? null : this.resolveJavaResourcePackageFragmentRoot_();
}
/**
* pre-condition: 'fileName' is neither null nor empty
*/
protected JavaResourcePackageFragmentRoot resolveJavaResourcePackageFragmentRoot_() {
// first, attempt to resolve location specifically...
JavaResourcePackageFragmentRoot jrpfr = this.resolveJrpfrOnDeploymentPath();
// ...then guess, basically
return (jrpfr != null) ? jrpfr : this.resolveJrpfrBestMatch();
}
/**
* pre-condition: 'fileName' is neither null nor empty
*/
protected JavaResourcePackageFragmentRoot resolveJrpfrOnDeploymentPath() {
for (IPath runtimePath : this.buildRuntimeJarFilePath(new Path(this.fileName))) {
IVirtualFile virtualJar = ComponentCore.createFile(this.getProject(), runtimePath);
IFile realJar = virtualJar.getUnderlyingFile();
if (realJar.exists() && realJar.getProject().equals(this.getProject())) {
return this.getJpaProject().getJavaResourcePackageFragmentRoot(realJar.getProjectRelativePath().toString());
}
}
return null;
}
/**
* Return an array of runtime paths that may correspond
* to the given persistence.xml jar file entry
*/
protected IPath[] buildRuntimeJarFilePath(IPath jarFilePath) {
IPath root = this.getJarRuntimeRootPath();
return this.projectHasWebFacet() ?
this.buildRuntimeJarFilePathWeb(root, jarFilePath) :
this.buildRuntimeJarFilePathNonWeb(root, jarFilePath);
}
protected IPath getJarRuntimeRootPath() {
return JptJpaCorePlugin.getJarRuntimeRootPath(this.getProject());
}
protected boolean projectHasWebFacet() {
return JptJpaCorePlugin.projectHasWebFacet(this.getProject());
}
protected IPath[] buildRuntimeJarFilePathWeb(IPath root, IPath jarFilePath) {
return new IPath[] {
// first path entry assumes form "../lib/other.jar"
root.append(jarFilePath.removeFirstSegments(1)),
// second path entry assumes form of first, without ".." ("lib/other.jar")
root.append(jarFilePath)
};
}
protected IPath[] buildRuntimeJarFilePathNonWeb(IPath root, IPath jarFilePath) {
return new IPath[] {
// assumes form "../lib/other.jar"
root.append(jarFilePath)
};
}
protected IProject getProject() {
return this.getJpaProject().getProject();
}
/**
* pre-condition: 'fileName' is neither null nor empty
*/
protected JavaResourcePackageFragmentRoot resolveJrpfrBestMatch() {
String jarFileName = new Path(this.fileName).lastSegment();
for (JpaFile jpaFile : this.getJpaProject().getJarJpaFiles()) {
if (jpaFile.getFile().getName().equals(jarFileName)) {
return (JavaResourcePackageFragmentRoot) jpaFile.getResourceModel();
}
}
return null;
}
/**
* pre-condition: 'jrpfr' is not null
*/
protected JarFile buildJarFile(JavaResourcePackageFragmentRoot jrpfr) {
return this.getContextNodeFactory().buildJarFile(this, jrpfr);
}
// ********** JarFileRef implementation **********
public XmlJarFileRef getXmlJarFileRef() {
return this.xmlJarFileRef;
}
public PersistentType getPersistentType(String typeName) {
return (this.jarFile == null) ? null : this.jarFile.getPersistentType(typeName);
}
public boolean containsOffset(int textOffset) {
return (this.xmlJarFileRef != null) && this.xmlJarFileRef.containsOffset(textOffset);
}
// ********** PersistentTypeContainer implementation **********
public Iterable<? extends PersistentType> getPersistentTypes() {
return (this.jarFile != null) ? this.jarFile.getPersistentTypes() : EmptyIterable.<JavaPersistentType>instance();
}
// ********** XmlContextNode implementation **********
public TextRange getValidationTextRange() {
return (this.xmlJarFileRef == null) ? null : this.xmlJarFileRef.getValidationTextRange();
}
// ********** refactoring **********
public Iterable<ReplaceEdit> createReplaceFolderEdits(IFolder originalFolder, String newName) {
return this.isIn(originalFolder) ?
new SingleElementIterable<ReplaceEdit>(this.createReplaceFolderEdit(originalFolder, newName)) :
EmptyIterable.<ReplaceEdit>instance();
}
protected ReplaceEdit createReplaceFolderEdit(IFolder originalFolder, String newName) {
return this.xmlJarFileRef.createReplaceFolderEdit(originalFolder, newName);
}
protected boolean isIn(IFolder folder) {
return (this.jarFile != null) && this.jarFile.isIn(folder);
}
// ********** validation **********
@Override
public void validate(List<IMessage> messages, IReporter reporter) {
super.validate(messages, reporter);
if (StringTools.stringIsEmpty(this.xmlJarFileRef.getFileName())) {
messages.add(
DefaultJpaValidationMessages.buildMessage(
IMessage.HIGH_SEVERITY,
JpaValidationMessages.PERSISTENCE_UNIT_UNSPECIFIED_JAR_FILE,
this,
this.getValidationTextRange()
)
);
return;
}
messages.add(
DefaultJpaValidationMessages.buildMessage(
IMessage.NORMAL_SEVERITY,
JpaValidationMessages.PERSISTENCE_UNIT_JAR_FILE_DEPLOYMENT_PATH_WARNING,
this,
this.getValidationTextRange()
)
);
if (this.jarFile == null) {
messages.add(
DefaultJpaValidationMessages.buildMessage(
IMessage.HIGH_SEVERITY,
JpaValidationMessages.PERSISTENCE_UNIT_NONEXISTENT_JAR_FILE,
new String[] {this.xmlJarFileRef.getFileName()},
this,
this.getValidationTextRange()
)
);
return;
}
this.jarFile.validate(messages, reporter);
}
// ********** overrides **********
@Override
public PersistenceUnit getParent() {
return (PersistenceUnit) super.getParent();
}
@Override
public void toString(StringBuilder sb) {
super.toString(sb);
sb.append(this.fileName);
}
}