blob: 9d0121baa29e883e4bb42487f80a691c63ca9595 [file] [log] [blame]
/*
* 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.uima.caseditor.core.model;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.caseditor.CasEditorPlugin;
import org.apache.uima.caseditor.core.model.delta.INlpElementDelta;
import org.apache.uima.caseditor.editor.AnnotationStyle;
import org.apache.uima.caseditor.editor.EditorAnnotationStatus;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
/**
* TODO: add comment
*/
public final class NlpProject extends AbstractNlpElement implements IProjectNature, INlpElement,
IAdaptable {
/**
* The ID of the <code>NLPProject</code>
*/
public static final String ID = "org.apache.uima.caseditor.NLPProject";
private static final String DOT_CORPUS_FILENAME = ".corpus";
private NlpModel mModel;
private IProject mProject;
private DotCorpusElement mDotCorpusElement;
private Collection<CorpusElement> mCopora = new LinkedList<CorpusElement>();
private Collection<CasProcessorFolder> mUimaSourceFolder = new LinkedList<CasProcessorFolder>();
private boolean mDotCorpusMustBeSerialized;
private boolean mIsDotCorpusDirty;
private EditorAnnotationStatus mEditorAnnotationStatus;
private TypesystemElement mTypesystem;
/**
* Initializes the current nlp project instance.
*
* @param model
*/
void setNlpModel(NlpModel model) {
mModel = model;
}
/**
* Initializes the current instance. This method is called before this instance can be used.
* Currently it recognizes and loads all nlp resources.
*
* Note: This method should only be called during static {@link NlpModel} creation.
*
* @throws CoreException
*/
void initialize() throws CoreException {
loadDotCorpus();
createCorpora();
for (CorpusElement corpus : getCorpora()) {
corpus.initialize();
}
createCasProcessorFolders();
// for (CasProcessorFolder sourceFolder : getCasProcessorFolders()) {
// sourceFolder.initialize();
// }
IFile typeSystemFile = getDotCorpus().getTypeSystemFile();
if (typeSystemFile != null && typeSystemFile.exists()) {
mTypesystem = new TypesystemElement(typeSystemFile, this);
}
if (getTypesystemElement() != null && getTypesystemElement().getTypeSystem() != null) {
TypeSystem typeSystem = getTypesystemElement().getTypeSystem();
Type annotationType = typeSystem.getType(CAS.TYPE_NAME_ANNOTATION);
List<Type> displayTypes = typeSystem.getProperlySubsumedTypes(annotationType);
// removes the document annotation
displayTypes.remove(typeSystem.getType(CAS.TYPE_NAME_DOCUMENT_ANNOTATION));
mEditorAnnotationStatus = new EditorAnnotationStatus(annotationType.getName(), displayTypes);
}
}
/**
* Retrieves the name.
*/
public String getName() {
return mProject.getName();
}
/**
* Retrieves the resource.
*/
public IResource getResource() {
return getProject();
}
/**
* Retrieves the parent element {@link NlpModel}.
*/
public INlpElement getParent() {
return mModel;
}
/**
* Not implemented, called to configure the project
*/
public void configure() throws CoreException {
// not implemented
}
/**
* Not implemented, called to de-configure the project
*/
public void deconfigure() throws CoreException {
// not implemented
}
/**
* Retrieves the {@link IProject}.
*/
public IProject getProject() {
return mProject;
}
/**
* Sets the {@link IProject}.
*/
public void setProject(IProject project) {
mProject = project;
}
/**
* Retrieves the {@link EditorAnnotationStatus} for the current project instance.
*
* @return status
*/
public EditorAnnotationStatus getEditorAnnotationStatus() {
return mEditorAnnotationStatus;
}
/**
* Sets the {@link EditorAnnotationStatus} for the current project instance.
*
* @param status
*/
public void setEditorAnnotationStatus(EditorAnnotationStatus status) {
mEditorAnnotationStatus = status;
}
private void loadDotCorpus() {
IResource dotCorpusResource = getProject().getFile(DOT_CORPUS_FILENAME);
mDotCorpusElement = DotCorpusElement.createDotCorpus((IFile) dotCorpusResource, this);
// TODO: What happens when there is a folder with the name ".corpus"
// then load default .corpus ...
}
/**
* Retrieves the corpora.
*
* @return the corpus collection
*/
public Collection<CorpusElement> getCorpora() {
return mCopora;
}
private void createCorpora() {
for (IFolder corpusFolderName : mDotCorpusElement.getCorpusFolderNameList()) {
if (corpusFolderName.exists()) {
CorpusElement corpusElement = new CorpusElement(this, corpusFolderName);
mCopora.add(corpusElement);
}
}
}
/**
* Retrieves all non-nlp resources of the current instance.
*
* @return the resources
* @throws CoreException
*/
public IResource[] getResources() throws CoreException {
IResource[] resources;
resources = mProject.members();
LinkedList<IResource> resourceList = new LinkedList<IResource>();
for (IResource element : resources) {
if (isSpecialResource(element)) {
continue;
}
if (element instanceof IFolder) {
if (mDotCorpusElement.isCorpusFolder((IFolder) element)) {
continue;
}
if (mDotCorpusElement.isCasProcessorFolder((IFolder) element)) {
continue;
}
}
if (mTypesystem != null && mTypesystem.getResource().equals(element)) {
continue;
}
resourceList.add(element);
}
IResource[] filteredResources = new IResource[resourceList.size()];
return resourceList.toArray(filteredResources);
}
/**
* Retrieves the parent element for the given resource.
*/
@Override
public INlpElement getParent(IResource resource) throws CoreException {
INlpElement result = super.getParent(resource);
if (result == null) {
if (mDotCorpusElement != null) {
if (mDotCorpusElement.getResource().equals(resource)) {
return this;
}
}
if (mTypesystem != null) {
if (mTypesystem.getResource().equals(resource)) {
return this;
}
}
for (IResource candiadte : getResources()) {
if (candiadte.equals(resource)) {
return this;
}
}
for (CorpusElement corpus : getCorpora()) {
INlpElement element = corpus.getParent(resource);
if (element != null) {
return element;
}
}
for (CasProcessorFolder sourceFolder : getCasProcessorFolders()) {
INlpElement element = sourceFolder.getParent(resource);
if (element != null) {
return element;
}
}
}
return null;
}
/**
* Searches the {@link INlpElement} for the given resource.
*/
@Override
public INlpElement findMember(IResource resource) {
INlpElement result = super.findMember(resource);
if (result == null) {
if (DOT_CORPUS_FILENAME.equals(resource.getName())) {
return mDotCorpusElement;
} else if (mTypesystem != null && mTypesystem.findMember(resource) != null) {
return mTypesystem.findMember(resource);
}
for (CasProcessorFolder sourceFolder : getCasProcessorFolders()) {
boolean isElementFound = sourceFolder.findMember(resource) != null;
if (isElementFound) {
return sourceFolder.findMember(resource);
}
}
for (CorpusElement corpus : getCorpora()) {
boolean isElementFound = corpus.findMember(resource) != null;
if (isElementFound) {
return corpus.findMember(resource);
}
}
}
return result;
}
/**
* Retrieves the UimaSourceFolder
*
* @return the UimaSourceFolder
*/
public Collection<CasProcessorFolder> getCasProcessorFolders() {
return mUimaSourceFolder;
}
private void createCasProcessorFolders() throws CoreException {
for (IFolder processorFolder : mDotCorpusElement.getCasProcessorFolders()) {
if (processorFolder.exists()) {
CasProcessorFolder processorElement = new CasProcessorFolder(processorFolder, this);
mUimaSourceFolder.add(processorElement);
}
}
}
/**
* Retrieves the {@link DotCorpusElement}.
*
* @return the {@link DotCorpusElement}
*/
public DotCorpusElement getDotCorpus() {
Assert.isTrue(mDotCorpusElement != null);
return mDotCorpusElement;
}
/**
* Retrieves the {@link NlpProject}.
*/
public NlpProject getNlpProject() {
return this;
}
private boolean isSpecialResource(IResource resource) {
String specialResource[] = { ".project", DOT_CORPUS_FILENAME };
for (String element : specialResource) {
if (resource.getName().equals(element)) {
return true;
}
}
return false;
}
private void updateAnnotationTypeColors() throws CoreException {
Collection<AnnotationStyle> styles = getDotCorpus().getAnnotationStyles();
if (getTypesystemElement() != null) {
TypeSystem ts = getTypesystemElement().getTypeSystem();
if (ts != null) {
Collection<AnnotationStyle> newStyles = DefaultColors.assignColors(ts, styles);
for (AnnotationStyle style : newStyles) {
getDotCorpus().setStyle(style);
}
if (styles.size() != newStyles.size()) {
mDotCorpusMustBeSerialized = true;
}
}
}
}
/**
* Adds a resource to the current project instance.
*/
@Override
public void addResource(INlpElementDelta delta, IResource resource) throws CoreException {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
if (DOT_CORPUS_FILENAME.equals(file.getName())) {
mIsDotCorpusDirty = true;
}
// if type system is set, it could had been renamed
else if (mDotCorpusElement.getTypeSystemFile() != null
&& (delta.getFlags() & IResourceDelta.MOVED_FROM) > 0
&& mDotCorpusElement.getTypeSystemFile().getFullPath().equals(
delta.getMovedFromPath())) {
// rename type system in dot corpus
mDotCorpusElement.setTypeSystemFilename(resource.getName());
// dot corpus was changed and must be writen
// do this after the delta processing
Runnable serialze = new Runnable() {
public void run() {
try {
mDotCorpusElement.serialize();
} catch (CoreException e) {
CasEditorPlugin.log(e);
}
}
};
((NlpModel) getNlpProject().getParent()).asyncExcuteQueue(serialze);
}
// check if file is type system
else if (mDotCorpusElement.getTypeSystemFile() != null
&& mDotCorpusElement.getTypeSystemFile().equals(resource)) {
mTypesystem = new TypesystemElement((IFile) resource, this);
updateAnnotationTypeColors();
}
} else if (resource instanceof IFolder) {
// corpus
if (mDotCorpusElement.isCorpusFolder((IFolder) resource)) {
mCopora.add(new CorpusElement(getNlpProject(), (IFolder) resource));
} else if (mDotCorpusElement.isCasProcessorFolder((IFolder) resource)) {
mUimaSourceFolder.add(new CasProcessorFolder((IFolder) resource, getNlpProject()));
}
}
}
/**
* Removes a resource form the current project instance.
*/
@Override
public void removeResource(INlpElementDelta delta, IResource resource) {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
if (DOT_CORPUS_FILENAME.equals(file.getName())) {
mIsDotCorpusDirty = true;
}
if (mTypesystem != null && resource.equals(mTypesystem.getResource())) {
mTypesystem = null;
}
}
for (CasProcessorFolder sourceFolder : mUimaSourceFolder) {
if (sourceFolder.getResource().equals(resource)) {
mUimaSourceFolder.remove(sourceFolder);
break;
}
}
for (CorpusElement corpus : mCopora) {
if (corpus.getResource().equals(resource)) {
mCopora.remove(corpus);
break;
}
}
}
@Override
void changedResource(IResource resource, INlpElementDelta delta) throws CoreException {
if (DOT_CORPUS_FILENAME.equals(resource.getName())) {
mIsDotCorpusDirty = true;
} else if (mTypesystem != null && resource.equals(mTypesystem.getResource())) {
mTypesystem.changedResource(resource, delta);
if (getTypesystemElement().getTypeSystem() != null) {
updateAnnotationTypeColors();
mEditorAnnotationStatus = new EditorAnnotationStatus(CAS.TYPE_NAME_ANNOTATION, null);
}
}
}
void postProcessResourceChanges() throws CoreException {
if (mIsDotCorpusDirty) {
mIsDotCorpusDirty = false;
mDotCorpusElement = null;
loadDotCorpus();
mUimaSourceFolder.clear();
mCopora.clear();
mTypesystem = null;
initialize();
updateAnnotationTypeColors();
CasEditorPlugin.getNlpModel().fireRefreshEvent(this);
}
if (mDotCorpusMustBeSerialized) {
Runnable writeDotCorpus = new Runnable() {
public void run() {
try {
getDotCorpus().serialize();
} catch (CoreException e) {
CasEditorPlugin.log(e);
}
}
};
CasEditorPlugin.getNlpModel().asyncExcuteQueue(writeDotCorpus);
}
}
/**
* Uses the {@link #getName()} to generate the hash code.
*/
@Override
public int hashCode() {
return getName().hashCode();
}
/**
* Tests if the given object is equal to the current instance.
*/
@Override
public boolean equals(Object obj) {
boolean isEqual;
if (obj != null && obj instanceof NlpProject) {
NlpProject project = (NlpProject) obj;
isEqual = getResource().equals(project.getResource());
} else {
isEqual = false;
}
return isEqual;
}
/**
* Adds a NLP nature to a project.
*
* @param project
* the project to add the nature
*
* @throws CoreException
*/
public static void addNLPNature(IProject project) throws CoreException {
IProjectDescription description = project.getDescription();
String[] natures = description.getNatureIds();
String[] newNatures = new String[natures.length + 1];
System.arraycopy(natures, 0, newNatures, 0, natures.length);
newNatures[natures.length] = NlpProject.ID;
description.setNatureIds(newNatures);
project.setDescription(description, null);
}
/**
* Retrieves the type system.
*
* @return type system
*/
public TypesystemElement getTypesystemElement() {
return mTypesystem;
}
}