/** * 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) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. * <p> */ package org.olat.ims.cp.objects; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; import org.dom4j.tree.DefaultElement; import org.olat.core.logging.OLATRuntimeException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.CodeHelper; import org.olat.ims.cp.CPCore; /** * * Description:<br> * This class represents an item-element of a IMS-manifest-file * * <P> * Initial Date: 26.06.2008 <br> * * @author Sergio Trentini */ public class CPItem extends DefaultElement implements CPNode { private String identifier; private String identifierRef; private String title; private CPMetadata metadata; private int position; private DefaultElement parent; private boolean visible; private Vector<CPItem> items; private Vector<String> errors; private OLog log; /** * constructor is needed while building the datamodel-tree (parsing XML) * * @param me */ public CPItem(DefaultElement me, DefaultElement parent) { super(me.getName()); items = new Vector<CPItem>(); errors = new Vector<String>(); log = Tracing.createLoggerFor(this.getClass()); // setAttributes(me.attributes()); setContent(me.content()); this.parent = parent; this.identifier = me.attributeValue(CPCore.IDENTIFIER); this.identifierRef = me.attributeValue(CPCore.IDENTIFIERREF, ""); String val = me.attributeValue(CPCore.ISVISIBLE, "true"); this.visible = (val != null && val.equals("true")); } /** * Constructor is needed when generating a new Item (e.g. adding a new Item to * the CP) */ public CPItem(String identifier) { super(CPCore.ITEM); log = Tracing.createLoggerFor(this.getClass()); visible = true; this.identifier = identifier; this.identifierRef = ""; items = new Vector<CPItem>(); errors = new Vector<String>(); } public CPItem() { this(CodeHelper.getGlobalForeverUniqueID()); } /** * * @see org.olat.ims.cp.objects.CPNode#buildChildren() */ public void buildChildren() { Iterator<DefaultElement> children = this.elementIterator(); // iterate through children while (children.hasNext()) { DefaultElement child = children.next(); if (child.getName().equals(CPCore.ITEM)) { CPItem item = new CPItem(child, this); item.buildChildren(); item.setPosition(items.size()); item.setParentElement(this); items.add(item); } else if (child.getName().equals(CPCore.TITLE)) { title = child.getText(); } else if (child.getName().equals(CPCore.METADATA)) { // TODO: implement LOM METADATA metadata = new CPMetadata(child); metadata.setParentElement(this); } } this.clearContent(); validateElement(); } /** * * @see org.olat.ims.cp.objects.CPNode#validateElement() */ public boolean validateElement() { if (this.title == null || this.title.equals("")) { errors.add("Invalid IMS-Manifest (missing \"title\" element in item " + this.identifier + " )"); return false; } if (this.identifier == null || this.identifier.equals("")) { errors.add("Invalid IMS-Manifest (missing \"identifier\" attribute in item " + this.identifier + " )"); return false; } return true; } /** * * @see org.olat.ims.cp.objects.CPNode#getXML(java.lang.StringBuilder) */ public void buildDocument(DefaultElement parent) { if(!validateElement()) return; DefaultElement itemElement = new DefaultElement(CPCore.ITEM); itemElement.addAttribute(CPCore.IDENTIFIER, identifier); if (!identifierRef.equals("")) itemElement.addAttribute(CPCore.IDENTIFIERREF, identifierRef); itemElement.addAttribute(CPCore.ISVISIBLE, isVisibleString()); if (metadata != null) { metadata.buildDocument(itemElement); } DefaultElement titleElement = new DefaultElement(CPCore.TITLE); titleElement.setText(title); itemElement.add(titleElement); for (Iterator<CPItem> itItem = items.iterator(); itItem.hasNext();) { CPItem item = itItem.next(); item.buildDocument(itemElement); } parent.add(itemElement); } // *** CP manipulation *** /** * adds a new CPItem to the childrens-list of this item (inserts at the end) * * @param newItem the new CPItem to add */ public void addItem(CPItem newItem) { newItem.setParentElement(this); items.add(newItem); newItem.setPosition(items.size() - 1); log.info("addItem: added " + newItem.getIdentifier() + " to " + this.getIdentifier()); } /** * adds a new CPItem to the childrens-list of this item at position index * * @param newItem the new CPItem to add * @param index position */ public void addItemAt(CPItem newItem, int index) { newItem.setParentElement(this); if (index > -1 && index <= items.size()) { items.add(index, newItem); newItem.setPosition(index); } else { addItem(newItem); } } /** * removes this item from the manifest */ public void removeFromManifest() { if (parent.getClass().equals(CPItem.class)) { CPItem p = (CPItem) parent; p.removeChild(identifier); } else if (parent.getClass().equals(CPOrganization.class)) { CPOrganization p = (CPOrganization) parent; p.removeChild(identifier); } } /** * removes a child <item> */ public void removeChild(String id) { boolean removed = false; for (Iterator<CPItem> itItem = items.iterator(); itItem.hasNext();) { CPItem item = itItem.next(); if (item.getIdentifier().equals(id)) { items.remove(item); removed = true; break; } } if (!removed) { throw new OLATRuntimeException(CPOrganizations.class, "error while removing child: child-element with identifier \"" + id + "\" not found!", new Exception()); } } /** * @see org.dom4j.tree.DefaultElement#clone() */ public Object clone() { CPItem copy = (CPItem) super.clone(); copy.setIdentifier(CodeHelper.getGlobalForeverUniqueID()); copy.setTitle(title + " copy"); // Since metadata cannot be edited for now we don't do a shallow // copy. The parent remains the same as well, so does the logger. // The subitems should be cloned though. Vector<CPItem> clonedItems = (Vector<CPItem>) items.clone(); copy.items = clonedItems; for (CPItem item : items) { int index = items.indexOf(item); CPItem clonedItem = (CPItem) item.clone(); clonedItem.setParentElement(copy); clonedItems.set(index, clonedItem); } return copy; } /** * Returns true, if item is visible * * @return boolean */ public boolean isVisible() { return this.visible; } /** * return "true" if item is visible "false" otherwise * * @return */ public String isVisibleString() { if (this.isVisible()) return "true"; return "false"; } // *** GETTERS *** /** * Returns the Item with the specified identifier Returns null if Item is not * found * * @param identifier id * @return CPItem or null */ public CPItem getItemByID(String id) { Iterator<CPItem> it = items.iterator(); CPItem item; while (it.hasNext()) { item = it.next(); if (item.getIdentifier().equals(id)) { return item; } } // TODO: should it throw an exception, if no element with the given // identifier is found ??? return null; } /** * @see org.olat.ims.cp.objects.CPNode#getElementByIdentifier(java.lang.String) */ public DefaultElement getElementByIdentifier(String id) { if (identifier.equals(id)) return this; DefaultElement e; for (Iterator<CPItem> it = items.iterator(); it.hasNext();) { CPItem item = it.next(); e = item.getElementByIdentifier(id); if (e != null) return e; } return null; } public String getTitle() { return this.title; } public String getIdentifier() { return this.identifier; } public String getIdentifierRef() { return this.identifierRef; } public int getPosition() { return position; } /** * searches for the first item with a linked resource (identifierRef id not * "") within the children items of this element if this element itself has a * referenced resource, this item is returned if no resource is found, null is * returned * * @return */ public CPItem getFirstItemWithResource() { if (this.identifierRef != "") { // this item has a linked resource return this; } else { if (items.size() < 1) return null; int i = 0; CPItem it = items.elementAt(i); while (it.identifierRef == "" && i < items.size()) { it = items.elementAt(i); i++; } if (it.identifierRef == "") { return null; } return it; } } public DefaultElement getParentElement() { return parent; } public CPMetadata getMetadata() { return metadata; } public Vector<CPItem> getItems() { return items; } public List<String> getItemIdentifiers() { List<String> ids = new ArrayList<String>(); for (CPItem item : items) { ids.add(item.getIdentifier()); } return ids; } /** * returns a Vector which holds all the children and its subchildren etc. * * @return */ public Vector<CPItem> getAllItems() { Vector<CPItem> allItems = new Vector<CPItem>(); allItems.addAll(this.getItems()); for (Iterator<CPItem> it = items.iterator(); it.hasNext();) { CPItem item = it.next(); allItems.addAll(item.getAllItems()); } return allItems; } public Iterator<CPItem> getItemIterator() { return items.iterator(); } /** * * @return */ String getLastError() { if (errors.size() > 0) return errors.lastElement(); return null; } // *** SETTERS *** public void setTitle(String title) { this.title = title; } public void setIdentifier(String identifier) { this.identifier = identifier; } public void setIdentifierRef(String identifierRef) { this.identifierRef = identifierRef; } public void setVisible(boolean visible) { this.visible = visible; } public void setPosition(int position) { this.position = position; } public void setParentElement(DefaultElement parent) { if (parent.getClass().equals(CPItem.class) || parent.getClass().equals(CPOrganization.class)) { this.parent = parent; } else { throw new OLATRuntimeException(CPOrganizations.class, "error while setting parentElement in element \"" + this.identifier + "\". Only <item> or <organization> as parent-element allowed", new Exception()); } } public void setMetadata(CPMetadata md) { metadata = md; } /** * generates a new system-unique identifier and sets it */ public void setNewUniqueID() { identifier = CodeHelper.getGlobalForeverUniqueID(); } /** * generates new system-unique ids for this element and all it's children * * @deprecated */ public void setNewUniqueIDrev() { identifier = CodeHelper.getGlobalForeverUniqueID(); for (Iterator<CPItem> it = items.iterator(); it.hasNext();) { CPItem item = it.next(); item.setNewUniqueIDrev(); } } }