/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2007 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.ims.cp;
import java.io.IOException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.dom4j.tree.DefaultDocument;
import org.dom4j.tree.DefaultElement;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.Encoder;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.ims.cp.objects.CPFile;
import org.olat.ims.cp.objects.CPItem;
import org.olat.ims.cp.objects.CPManifest;
import org.olat.ims.cp.objects.CPOrganization;
import org.olat.ims.cp.objects.CPOrganizations;
import org.olat.ims.cp.objects.CPResource;
import org.olat.ims.cp.ui.CPPage;
/**
* This class represents an IMS Content-Package. Most of the functionality is
* delegated to cpcore (@see org.olat.ims.cp.CPCOre)
*
* <P>
* Initial Date: 27.06.2008 <br>
*
* @author Sergio Trentini
*/
public class ContentPackage {
// Delegate
private CPCore cpcore;
private OLATResourceable ores;
private static final OLog log = Tracing.createLoggerFor(ContentPackage.class);
// *** constructors ***
ContentPackage(DefaultDocument doc, VFSContainer parent, OLATResourceable ores) {
this.cpcore = new CPCore(doc, parent);
this.ores = ores;
}
// *** CP manipulation ***
String addBlankPage(String title) {
CPItem newPage = new CPItem();
newPage.setTitle(title);
cpcore.addElement(newPage);
return newPage.getIdentifier();
}
String addBlankPage(String parentID, String title) {
CPItem newPage = new CPItem();
newPage.setTitle(title);
cpcore.addElement(newPage, parentID, 0);
return newPage.getIdentifier();
}
protected void updatePage(CPPage page) {
DefaultElement ele = cpcore.getElementByIdentifier(page.getIdentifier());
if (ele instanceof CPItem) {
CPItem item = (CPItem) ele;
item.setTitle(page.getTitle());
item.setMetadata(page.getMetadata());
String itemIdentifierRef = item.getIdentifierRef();
if (itemIdentifierRef == null || itemIdentifierRef.equals("")) {
// This item has no linked resource yet. Add one if there is a page file
// attached.
VFSLeaf pageFile = page.getPageFile();
if (pageFile != null) {
CPResource res = new CPResource();
CPFile file = new CPFile(pageFile);
res.addFile(file);
// TODO:GW Set type according to file
res.setType("text/html");
res.setHref(file.getHref());
item.setIdentifierRef(res.getIdentifier());
cpcore.getRootNode().getResources().addResource(res);
}
} else {// this item has already a linked resource
// this is not supported, we don't change linked resources...
}
} else if (ele instanceof CPOrganization) {
CPOrganization organization = (CPOrganization) ele;
organization.setTitle(page.getTitle());
} else {
// ERROR: this shouldn't be
throw new OLATRuntimeException("Error while updating manifest with new Page-Data. Invalid identifier " + page.getIdentifier(), null);
}
}
boolean addElement(DefaultElement newElement, String parentId, int position) {
return cpcore.addElement(newElement, parentId, position);
}
boolean addElement(DefaultElement newElement) {
cpcore.addElement(newElement);
return true;
}
boolean addElementAfter(DefaultElement newElement, String id) {
return cpcore.addElementAfter(newElement, id);
}
void removeElement(String identifier, boolean deleteResource) {
// at the moment, we remove always with resources (if they are not linked
// in another item)
cpcore.removeElement(identifier, deleteResource);
}
void moveElement(String nodeID, String newParentID, int position) {
if (nodeID.equals(newParentID)) throw new OLATRuntimeException(CPOrganizations.class,
"error while moving element: source and destination are identical...", new Exception());
cpcore.moveElement(nodeID, newParentID, position);
}
String copyElement(String sourceID, String targetID) {
return cpcore.copyElement(sourceID, targetID);
}
/**
* writes the manifest.xml
*/
void writeToFile() {
String filename = "imsmanifest.xml";
OutputFormat format = OutputFormat.createPrettyPrint();
try {
VFSLeaf outFile;
// file may exist
outFile = (VFSLeaf) cpcore.getRootDir().resolve("/" + filename);
if (outFile == null) {
// if not, create it
outFile = cpcore.getRootDir().createChildLeaf("/" + filename);
}
DefaultDocument manifestDocument = cpcore.buildDocument();
XMLWriter writer = new XMLWriter(outFile.getOutputStream(false), format);
writer.write(manifestDocument);
} catch (Exception e) {
log.error("imsmanifest for ores " + ores.getResourceableId() + "couldn't be written to file.", e);
throw new OLATRuntimeException(CPOrganizations.class, "Error writing imsmanifest-file", new IOException());
}
}
// *** getters ***
protected boolean isSingleUsedResource(CPResource res) {
int linkCount = cpcore.referencesCount(res);
return (linkCount < 2);
}
public VFSContainer getRootDir() {
return cpcore.getRootDir();
}
protected DefaultDocument getDocument() {
return cpcore.buildDocument();
}
protected CPManifest getRootNode() {
return cpcore.getRootNode();
}
protected DefaultElement getElementByIdentifier(String identifier) {
return cpcore.getElementByIdentifier(identifier);
}
public CPOrganization getFirstOrganizationInManifest() {
return cpcore.getFirstOrganizationInManifest();
}
/**
* Return the treeDataModel used for GUI-tree
*
* @return
*/
protected CPTreeDataModel buildTreeDataModel() {
String orgaIdentifier = getFirstOrganizationInManifest().getIdentifier();
// For the root node id of the ext-js tree we use an md5 hash. This is to
// make sure that no unwanted characters are handed over to JS.
String rootNodeId = Encoder.encrypt(orgaIdentifier);
CPTreeDataModel treeData = new CPTreeDataModel(orgaIdentifier, rootNodeId);
treeData.setContentPackage(this);
return treeData;
}
protected CPPage getFirstPageToDisplay() {
CPItem it = cpcore.getFirstPageToDisplay();
if (it == null) {
// in case the manifest has no item at all -> use organisation identifyer
// instead
return new CPPage(cpcore.getFirstOrganizationInManifest().getIdentifier(), this);
} else {
// display the found item
return new CPPage(it.getIdentifier(), this);
}
}
protected String getPageByItemId(String itemID) {
return cpcore.getPageByItemID(itemID);
}
protected String getItemTitle(String itemID) {
return cpcore.getItemTitle(itemID);
}
public String getLastError() {
return cpcore.getLastError();
}
// *** SETTERS ***
public void setLastError(String error) {
cpcore.setLastError(error);
}
/**
* @return Returns a boolean value indicating whether the CP was created with
* the OLAT CP editor or not.
*/
public boolean isOLATContentPackage() {
return cpcore.isOLATContentPackage();
}
/**
* @return Returns the ores.
*/
public OLATResourceable getResourcable() {
return ores;
}
}