/**
* Copyright 2010 The University of North Carolina at Chapel Hill
*
* 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 unc.lib.cdr.workbench.project;
import edu.unc.lib.staging.SharedStagingArea;
import edu.unc.lib.staging.StagingArea;
import edu.unc.lib.staging.StagingException;
import gov.loc.mets.DivType;
import gov.loc.mets.DocumentRoot;
import gov.loc.mets.FLocatType;
import gov.loc.mets.FileGrpType;
import gov.loc.mets.FileType;
import gov.loc.mets.MetsType1;
import gov.loc.mets.util.METSConstants;
import gov.loc.mets.util.METSUtils;
import gov.loc.mods.mods.presentation.URIFragmentEditorInput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.osgi.service.prefs.BackingStoreException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import staging.plugin.StagingPlugin;
import unc.lib.cdr.workbench.arrange.ArrangementProjectElement;
import unc.lib.cdr.workbench.originals.OriginalFileStore;
import unc.lib.cdr.workbench.originals.OriginalStub;
import unc.lib.cdr.workbench.originals.OriginalsFileSystem;
import unc.lib.cdr.workbench.rcp.Activator;
public class MetsProjectNature implements IProjectNature {
private static final Logger LOG = LoggerFactory
.getLogger(MetsProjectNature.class);
private static final Logger log = LoggerFactory
.getLogger(MetsProjectNature.class);
public static final String NATURE_ID = "cdr_producer.projectNature";
public static final String STAGING_BUILDER_ID = "unc.lib.cdr.workbench.builders.StageBuilder";
public static final String CROSSWALKS_BUILDER_ID = "unc.lib.cdr.workbench.builders.CrosswalksBuilder";
private static final String STAGING_BASE_URI_KEY = "cdr_producer.stagingBaseURI";
private static final String ORIGINALS_KEY = "cdr_producer.originals";
private IProject project = null;
private ArrangementProjectElement arrangementElement = null;
private ArrayList<OriginalStub> originals = null;
private ProjectEMFSession emfSession;
public ArrangementProjectElement getArrangementElement() {
if (this.arrangementElement == null) {
this.arrangementElement = new ArrangementProjectElement(this);
}
return arrangementElement;
}
public MetsProjectNature() {
}
public Resource getMetsResource() {
return getEMFSession().getMetsResource();
}
public static ComposedAdapterFactory getAdapterFactory() {
return ProjectEMFSession.getAdapterFactory();
}
public CommandStack getCommandStack() {
return getEMFSession().getCommandStack();
}
public AdapterFactoryEditingDomain getEditingDomain() {
return getEMFSession().getEditingDomain();
}
public void save() throws CoreException {
if (this.getProject().isOpen()) {
if (this.getEMFSession() != null) {
this.getEMFSession().save();
}
saveOriginals();
}
}
/**
* @return
*/
public ProjectEMFSession getEMFSession() {
return this.emfSession;
}
public MetsType1 getMets() {
DocumentRoot r = (DocumentRoot) this.getEMFSession().getMetsResource()
.getContents().get(0);
return r.getMets();
}
@Override
public void configure() throws CoreException {
try {
// set up builders
IProjectDescription desc = this.getProject().getDescription();
boolean autostage = getAutomaticStaging();
setupBuildSpec(desc, autostage);
this.project.setDescription(desc, new NullProgressMonitor());
// this.project.setSessionProperty(EDITING_DOMAIN_KEY,
// editingDomain);
// this.project.setSessionProperty(RESOURCE_SET_KEY, resourceSet);
} catch (CoreException e) {
e.printStackTrace();
}
}
@Override
public void deconfigure() throws CoreException {
save();
}
@Override
public IProject getProject() {
return this.project;
}
@Override
public void setProject(IProject project) {
this.project = project;
IEclipsePreferences projectNode = new ProjectScope(project)
.getNode(Activator.PLUGIN_ID);
try {
projectNode.flush();
} catch (BackingStoreException e) {
e.printStackTrace();
}
this.emfSession = new ProjectEMFSession(project);
this.loadOriginals();
}
private void loadOriginals() {
IEclipsePreferences projectNode = new ProjectScope(project)
.getNode(Activator.PLUGIN_ID);
byte[] s = projectNode.getByteArray(ORIGINALS_KEY, null);
if (s == null) {
this.originals = new ArrayList<OriginalStub>();
} else {
try {
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(s));
this.originals = (ArrayList<OriginalStub>) in.readObject();
log.debug("loaded originals: {}", this.originals.size());
} catch (Exception e) {
throw new Error("Cannot deserialize originals for project", e);
}
}
}
private void saveOriginals() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(this.originals);
} catch (Exception e) {
throw new Error("Cannot serialize project originals", e);
}
IEclipsePreferences projectNode = new ProjectScope(project)
.getNode(Activator.PLUGIN_ID);
projectNode.putByteArray(ORIGINALS_KEY, baos.toByteArray());
try {
// project.refreshLocal(IResource.DEPTH_INFINITE, new
// NullProgressMonitor());
projectNode.flush();
} catch (BackingStoreException e) {
throw new Error(e);
}
log.debug("wrote originals to preferences");
}
public void addOriginal(OriginalStub o) {
this.originals.add(o);
// log.debug("adding original at: {}", o.getBase().toString());
this.saveOriginals();
}
public List<OriginalStub> getOriginals() {
return Collections.unmodifiableList(this.originals);
}
public static IProject getProjectForMetsEObject(EObject object) {
IProject result = null;
Resource objectResource = object.eResource();
if (objectResource != null) {
for (IProject p : ResourcesPlugin.getWorkspace().getRoot()
.getProjects()) {
if (p.isOpen()) {
MetsProjectNature n = MetsProjectNature.get(p);
if (n != null) {
Resource resource = n.getEMFSession().getMetsResource();
if (resource != null && objectResource.equals(resource)) {
return p;
}
}
}
}
}
return result;
}
public static MetsProjectNature getNatureForMetsObject(EObject object) {
IProject p = getProjectForMetsEObject(object);
MetsProjectNature result;
try {
result = (MetsProjectNature) p.getNature(NATURE_ID);
} catch (CoreException e) {
throw new Error("Workbench Project MUST have a MetsProjectNature");
}
return result;
}
public static EditingDomain getEditingDomain(EObject object) {
EditingDomain result = null;
IProject p = getProjectForMetsEObject(object);
if (p != null) {
try {
MetsProjectNature mpn = (MetsProjectNature) p
.getNature(MetsProjectNature.NATURE_ID);
result = mpn.getEditingDomain();
} catch (CoreException ignored) {
}
}
return result;
}
// public IFolder getOriginalsFolder() {
// return this.getProject().getFolder(ORIGINALS_FOLDER_NAME);
// }
public boolean getAutomaticStaging() {
boolean result = false;
ProjectScope[] s = { new ProjectScope(project) };
result = Platform.getPreferencesService().getBoolean(
Activator.PLUGIN_ID, Activator.AUTOSTAGE_PREFERENCE, true, s);
return result;
}
public void setAutomaticStaging(boolean auto) {
ProjectScope s = new ProjectScope(project);
IEclipsePreferences pref = s.getNode(Activator.PLUGIN_ID);
pref.putBoolean(Activator.AUTOSTAGE_PREFERENCE, auto);
}
/**
* Finds the original file or folder object for a given div or null.
*
* @param div
* @return the IResource of the original
*/
public static OriginalFileStore getOriginalFileStore(DivType div) {
if (div.getCONTENTIDS() != null && div.getCONTENTIDS().size() > 0) {
URI uri = null;
for (String contentid : div.getCONTENTIDS()) {
try {
uri = new URI(contentid);
} catch (URISyntaxException e) {
throw new Error(e);
}
if (!"info".equals(uri.getScheme()))
break;
}
return getNatureForMetsObject(div).getOriginal(uri);
}
return null;
}
/**
* Finds the original file or folder object for a given div or null.
*
* @param div
* @return the IResource of the original
*/
public static IFileStore getStagedFileStore(DivType div) {
MetsProjectNature mpn = MetsProjectNature.getNatureForMetsObject(div);
IFileStore result = null;
if(div.getFptr() != null && !div.getFptr().isEmpty()) {
String fileid = div.getFptr().get(0).getFILEID();
FileType ft = (FileType) mpn.getMetsResource().getEObject(fileid);
if (ft != null && ft.getFLocat() != null) {
for (FLocatType loc : ft.getFLocat()) {
if (METSConstants.FLocat_USE_STAGE.equals(loc.getUSE())) {
URI stagedLoc = URI.create(loc.getHref());
SharedStagingArea s = StagingPlugin.getDefault()
.getStages().findMatchingArea(stagedLoc);
if (!s.isConnected())
StagingPlugin.getDefault().getStages()
.connect(s.getURI());
try {
URI stagedStorageURI = StagingPlugin.getDefault()
.getStages().getStorageURI(stagedLoc);
stagedStorageURI = mpn
.resolveProjectRelativeURI(stagedStorageURI);
result = EFS.getStore(stagedStorageURI);
} catch(Throwable ignored) {}
}
}
}
}
return result;
}
public static OriginalFileStore getOriginal(FileType file) {
OriginalFileStore result = null;
if (file.getFLocat() != null && file.getFLocat().size() > 0) {
URI uri = null;
for (FLocatType locat : file.getFLocat()) {
try {
if (METSConstants.FLocat_USE_ORIGINAL
.equals(locat.getUSE())) {
uri = new URI(locat.getHref());
break;
}
} catch (URISyntaxException e) {
throw new Error(e);
}
}
if (uri != null) {
result = getNatureForMetsObject(file).getOriginal(uri);
}
}
return result;
}
public OriginalFileStore getOriginal(URI uri) {
OriginalFileStore result = null;
try {
IPath divPath = Path.fromOSString(uri.getPath());
OriginalStub mystub = null;
for (OriginalStub stub : getOriginals()) {
for (URI loc : stub.getLocations()) {
IPath stubPath = Path.fromOSString(loc.getPath());
if (stubPath.isPrefixOf(divPath)) {
mystub = stub;
break;
}
}
}
result = (OriginalFileStore) OriginalsFileSystem.wrapStore(uri,
mystub);
} catch (Exception ignored) {
}
return result;
}
/**
* @param prog
* @return
*/
public static MetsProjectNature get(IProject prog) {
MetsProjectNature result = null;
try {
result = (MetsProjectNature) prog.getNature(NATURE_ID);
} catch (CoreException e) {
}
return result;
}
/**
* @param stageURI
*/
public void setStagingBase(String stageURI) {
LOG.debug("setting stageURI to: {}", stageURI);
IEclipsePreferences projectNode = new ProjectScope(project)
.getNode(Activator.PLUGIN_ID);
projectNode.put(STAGING_BASE_URI_KEY, stageURI);
}
public java.net.URI getStagingManifestURI() {
try {
IEclipsePreferences projectNode = new ProjectScope(project)
.getNode(Activator.PLUGIN_ID);
String s = projectNode.get(STAGING_BASE_URI_KEY, null);
return new java.net.URI(s);
} catch (Exception e) {
throw new Error("unexpected", e);
}
}
public java.net.URI getStagingStorageURI() throws StagingException {
URI manifest = this.getStagingManifestURI();
StagingArea area = StagingPlugin.getDefault().getStages().findMatchingArea(manifest);
return area.getStorageURI(manifest);
}
public static void setupBuildSpec(IProjectDescription desc,
boolean autostage) {
// create staging builder
ICommand stagingCommand = desc.newCommand();
stagingCommand.setBuilderName(MetsProjectNature.STAGING_BUILDER_ID);
stagingCommand.setBuilding(IncrementalProjectBuilder.AUTO_BUILD,
autostage);
stagingCommand.setBuilding(IncrementalProjectBuilder.FULL_BUILD, true);
stagingCommand.setBuilding(IncrementalProjectBuilder.INCREMENTAL_BUILD,
true);
// add builders to project description
List<ICommand> builders = new ArrayList<ICommand>();
builders.add(stagingCommand);
desc.setBuildSpec(builders.toArray(new ICommand[1]));
}
public static EObject getModel(URIFragmentEditorInput in) {
IProject p = ResourcesPlugin.getWorkspace().getRoot()
.getProject(in.getProjectName());
MetsProjectNature n = MetsProjectNature.get(p);
return n.getEditingDomain().getResourceSet().getResources().get(0)
.getEObject(in.getFragmentID());
}
public String getDescriptionStatus() {
int numOfFiles = 0;
int numOfContainers = 0;
int numDescribed = 0;
TreeIterator<EObject> iter = METSUtils.findBagDiv(getMets())
.eAllContents();
try {
for (EObject eo = iter.next(); iter.hasNext(); eo = iter.next()) {
if (eo instanceof DivType) {
DivType d = (DivType) eo;
if (METSConstants.Div_File.equals(d.getTYPE())) {
numOfFiles++;
} else {
numOfContainers++;
}
if (d.getDmdSec() != null && d.getDmdSec().size() > 0) {
numDescribed++;
}
}
}
} catch (NoSuchElementException ignored) {
}
StringBuilder result = new StringBuilder().append(numOfFiles);
if (numOfFiles > 1) {
result.append(" file objects captured");
} else {
result.append(" file object captured");
}
result.append("\n").append(numOfContainers);
if (numOfContainers > 1 || numOfContainers == 0) {
result.append(" non-file objects");
} else {
result.append(" non-file object");
}
return result.append("\n").append(numDescribed)
.append(" objects are described").toString();
}
public String getStagingStatus() {
int[] stagedAndCaptured = countStagedAndCaptured(getProject());
int numStaged = stagedAndCaptured[0];
int numOfFiles = stagedAndCaptured[1];
StringBuilder result = new StringBuilder().append(numStaged)
.append(" out of ").append(numOfFiles);
if (numOfFiles > 1 || numOfFiles == 0) {
result.append(" files staged");
} else {
result.append(" file staged");
}
return result.toString();
}
public static int[] countStagedAndCaptured(IProject project) {
int numOfFiles = 0;
int numStaged = 0;
FileGrpType fileGrp = METSUtils.getObjectsFileGroup(MetsProjectNature.get(project).getMets());
for (TreeIterator<EObject> iter = fileGrp.eAllContents(); iter.hasNext();) {
EObject next = iter.next();
if (next != null && next instanceof FLocatType) {
FLocatType flocat = (FLocatType)next;
if(METSConstants.FLocat_USE_ORIGINAL.equals(flocat.getUSE())) {
numOfFiles++;
} else if(METSConstants.FLocat_USE_STAGE.equals(flocat.getUSE())) {
numStaged++;
}
}
}
return new int[] {numStaged, numOfFiles};
}
public URI resolveProjectRelativeURI(URI storageURI) {
URI result = storageURI;
if (!storageURI.isAbsolute()) {
URI projectURI = project.getLocationURI();
result = URI.create(projectURI.toString() + "/")
.resolve(storageURI);
}
return result;
}
}