/*******************************************************************************
* Copyright 2006 - 2014 Vienna University of Technology,
* Department of Software Technology and Interactive Systems, IFS
*
* 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 eu.scape_project.planning.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import org.slf4j.Logger;
import eu.scape_project.planning.manager.IByteStreamStorage;
import eu.scape_project.planning.model.DigitalObject;
import eu.scape_project.planning.model.Plan;
import eu.scape_project.planning.model.PlatoException;
import eu.scape_project.planning.model.tree.TemplateTree;
import eu.scape_project.planning.model.tree.TreeNode;
import eu.scape_project.planning.utils.OS;
/**
* Importer for Plato projects.
*/
@Stateful
@SessionScoped
@Named
public class ProjectImporter extends PlanXMLConstants implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private Logger log;
/**
* Used to store digital objects after de-serializing a plan.
*/
@Inject
private IByteStreamStorage storage;
@Inject
private EntityManager em;
private List<String> appliedTransformations = new ArrayList<String>();
private PlanParser planParser = new PlanParser();
/**
* Deserializes the plans in the provided inputstream.
*
* @param plans
* the plans to import
* @return a list of imported plans
* @throws PlatoException
* if an error occurred
*/
public List<Plan> importPlans(final InputStream plans) throws PlatoException {
appliedTransformations.clear();
String tempPath = OS.getTmpPath() + "import_xml" + System.currentTimeMillis() + File.separator;
File tempDir = new File(tempPath);
tempDir.deleteOnExit();
tempDir.mkdirs();
try {
PlanMigrator planMigrator = new PlanMigrator();
String currentVersionFile = planMigrator.getCurrentVersionData(plans, tempPath, appliedTransformations);
if (currentVersionFile == null) {
log.error("Failed to migrate plans.");
return new ArrayList<Plan>();
} else {
return planParser.importProjects(new FileInputStream(currentVersionFile));
}
} catch (FileNotFoundException e) {
throw new PlatoException("IMPORT FAILED: could not find migrated file", e);
} finally {
OS.deleteDirectory(tempDir);
}
}
/**
* Deserializes the plans in the provided file.
*
* @param file
* the plans to import
* @return a list of imported plans
* @throws PlatoException
* if an error occurred
*/
public List<Plan> importPlans(final String file) throws PlatoException {
try {
return importPlans(new FileInputStream(file));
} catch (FileNotFoundException e) {
throw new PlatoException("IMPORT FAILED: could not find file " + file, e);
}
}
/**
* Imports all plans from the given file and stores them in the database.
*
* @param file
* the file to import
* @throws PlatoException
* if an error occured during import
*/
public void importPlans(final File file) throws PlatoException {
log.debug("importing file: " + file.getName());
for (Plan p : importPlans(file.getAbsolutePath())) {
storeDigitalObjects(p);
em.persist(p);
}
}
/**
* Imports all plans in the given directory and stores them in the database.
*
* @param dir
* directory to import from
* @return the number of successfully imported files
* @throws PlatoException
* if the import directory is not valid
*/
public int importAllProjectsFromDir(final String dir) throws PlatoException {
int count = 0;
File f = new File(dir);
if (!f.exists()) {
throw new PlatoException("Directory not found: " + dir);
}
String[] files = f.list();
if (files == null) {
throw new PlatoException("Directory is empty: " + dir);
}
List<String> sortedFiles = Arrays.asList(files);
Collections.sort(sortedFiles);
for (String s : sortedFiles) {
String file = f.getAbsolutePath() + File.separator + s;
File source = new File(file);
if (source.isFile() && s.endsWith(".xml")) {
log.info("Importing file: " + file);
List<Plan> plans = importPlans(file);
for (Plan p : plans) {
try {
storeDigitalObjects(p);
em.persist(p);
count++;
} catch (Exception e) {
log.error("failed to import plan: " + p.getPlanProperties().getId() + "-"
+ p.getPlanProperties().getName(), e);
}
}
}
}
log.info("finished import");
return count;
}
/**
* Stores byte streams of digital objects.
*
* @param p
* the plan to process
* @throws PlatoException
* if an error occurred
*/
public void storeDigitalObjects(final Plan p) throws PlatoException {
try {
List<DigitalObject> digitalObjects = p.getDigitalObjects();
for (DigitalObject o : digitalObjects) {
if (o.getData().getSize() > 0) {
String pid = storage.store(null, o.getData().getRealByteStream().getData());
o.setPid(pid);
o.getData().releaseData();
}
}
} catch (Exception e) {
throw new PlatoException(e);
}
}
/**
* Destroy method.
*/
@Remove
public void destroy() {
}
/**
* This method takes a template xml and stores the templates in the template
* library. The xml is of the form:
*
* <templates> <template name="Public Fragments"> <node name="Template 1"
* weight="0.0" single="false" lock="false"> <node
* name="Interactive multimedia presentations" weight="0.0" single="false"
* lock="false"> ... </template> </templates>
*
* We go through the templates //templates/template/node and store them in
* the respective template library, in this case 'Public Fragments'
*
* @param xml
* the templates as XML input stream
* @throws PlatoException
* if an error occurred
*/
public void storeTemplatesInLibrary(final InputStream xml) throws PlatoException {
List<TemplateTree> templates = planParser.importTemplates(xml);
/*
* store all templates
*/
for (TemplateTree template : templates) {
// we get the template tree ("Public Templates") from the database
TemplateTree tdb;
try {
tdb = (TemplateTree) em.createQuery("select n from TemplateTree n where name = :name")
.setParameter("name", template.getName()).getSingleResult();
} catch (NoResultException e) {
tdb = new TemplateTree(template.getName(), null);
}
if (tdb != null) {
// we get the templates and add them to the tree
// and store them
for (TreeNode n : template.getRoot().getChildren()) {
tdb.getRoot().addChild(n);
em.persist(n);
}
em.persist(em.merge(tdb));
em.flush();
}
}
}
// ********** getter/setter **********
public List<String> getAppliedTransformations() {
return appliedTransformations;
}
}