package com.delcyon.capo.xml.dom; import java.lang.reflect.Modifier; import java.util.List; import java.util.Vector; import java.util.logging.Level; import org.w3c.dom.DOMException; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.delcyon.capo.CapoApplication; import com.delcyon.capo.controller.ControlElement; import com.delcyon.capo.controller.elements.ResourceControlElement; import com.delcyon.capo.resourcemanager.ContentFormatType; import com.delcyon.capo.resourcemanager.ResourceDescriptor; import com.delcyon.capo.resourcemanager.ResourceParameter; import com.delcyon.capo.resourcemanager.ResourceParameterBuilder; import com.delcyon.capo.resourcemanager.ResourceURI; import com.delcyon.capo.resourcemanager.ResourceDescriptor.Action; import com.delcyon.capo.resourcemanager.ResourceDescriptor.DefaultParameters; import com.delcyon.capo.resourcemanager.types.ContentMetaData; import com.delcyon.capo.resourcemanager.types.SimpleContentMetaData; import com.delcyon.capo.util.CloneControl; import com.delcyon.capo.util.ControlledClone; import com.delcyon.capo.util.ToStringControl; import com.delcyon.capo.util.CloneControl.Clone; import com.delcyon.capo.util.ToStringControl.Control; import com.delcyon.capo.xml.cdom.CAttr; import com.delcyon.capo.xml.cdom.CDOMEvent; import com.delcyon.capo.xml.cdom.CDOMEventListener; import com.delcyon.capo.xml.cdom.CElement; import com.delcyon.capo.xml.cdom.CNamedNodeMap; import com.delcyon.capo.xml.cdom.CNode; import com.delcyon.capo.xml.cdom.CNodeList; import com.delcyon.capo.xml.cdom.VariableContainer; @CloneControl(filter=CloneControl.Clone.exclude,modifiers=Modifier.STATIC+Modifier.FINAL) @ToStringControl(control=Control.exclude,modifiers=Modifier.STATIC+Modifier.FINAL) public class ResourceElement extends CElement implements ControlledClone,ResourceNode, CDOMEventListener { @CloneControl(filter=Clone.exclude) @ToStringControl(control=Control.exclude) private ResourceDocument ownerResourceDocument; private ResourceDescriptor resourceDescriptor; private List<ContentMetaData> childResourceContentMetaData; private ContentMetaData contentMetaData; private boolean dynamic = true; private ResourceURI resourceURI; private CElement content; @SuppressWarnings("unused") private ResourceElement(){} //serialization only public ResourceElement(ResourceDocument ownerResourceDocument, String localName, CElement content,ContentMetaData contentMetaData) { super(CapoApplication.RESOURCE_NAMESPACE_URI,"resource",localName); this.ownerResourceDocument = ownerResourceDocument; setContent(content); this.dynamic = false; setContentMetatData(contentMetaData); } /** * This will pull the localName from the resourceDescriptor to use as it's localName * @param ownerResourceDocument * @param parentNode * @param resourceDescriptor * @throws Exception */ public ResourceElement(ResourceDocument ownerResourceDocument,ResourceNode parentNode,ResourceDescriptor resourceDescriptor) throws Exception { super(CapoApplication.RESOURCE_NAMESPACE_URI,"resource",resourceDescriptor.getLocalName()); this.ownerResourceDocument = ownerResourceDocument; this.resourceDescriptor = resourceDescriptor; this.dynamic = true; setContentMetatData(resourceDescriptor.getResourceMetaData(null)); } public void setContentMetatData(ContentMetaData contentMetaData) { this.contentMetaData = contentMetaData; this.resourceURI = contentMetaData.getResourceURI(); setResourceAttribute("uri", contentMetaData.getResourceURI().getResourceURIString()); setResourceAttribute("new",false+""); setResourceAttribute("modified",false+""); List<String> supportedAttributeList = contentMetaData.getSupportedAttributes(); for (String attributeName : supportedAttributeList) { if (contentMetaData.getValue(attributeName) != null) { ResourceAttr resourceAttr = new ResourceAttr(this,attributeName, contentMetaData.getValue(attributeName)); setResourceAttributeNode(resourceAttr); } } } @Override public void cascadeDOMEvent(CDOMEvent cdomEvent) { if (content == null || ownerResourceDocument.isFullDocument() == true) { super.cascadeDOMEvent(cdomEvent); } else if (cdomEvent != null) { processEvent(cdomEvent); if(getParentNode() != null && getParentNode() instanceof CNode) { ((CNode) getParentNode()).cascadeDOMEvent(cdomEvent); } } } @Override public Vector<CDOMEventListener> getCDOMEventListeners() { if(content == null || ownerResourceDocument.isFullDocument() == true) { return super.getCDOMEventListeners(); } else { return content.getCDOMEventListeners(); } } @Override public boolean hasEventListeners() { if(content == null || ownerResourceDocument.isFullDocument() == true) { return super.hasEventListeners(); } else { return content.hasEventListeners(); } } public boolean isContainter() { if(contentMetaData != null) { return contentMetaData.isContainer(); } return false; } @Override public void processEvent(CDOMEvent cdomEvent) { System.out.println(cdomEvent); if(cdomEvent.getSourceNode().equals(this)) { cdomEvent.setHandled(true); } setResourceAttribute("modified",true+""); } public void update(VariableContainer variableContainer, ControlElement callingControlElement, ResourceParameter... resourceParameters) throws Exception { if( (isNew() || isModified()) && isContainter() == false) { if(resourceDescriptor == null) { resourceDescriptor = getResourceControlElement().getParentGroup().getResourceDescriptor( callingControlElement, resourceURI.getResourceURIString()); resourceDescriptor.open(variableContainer,resourceParameters); } if(content == null && isModified()) { if (resourceDescriptor.getResourceMetaData(null).exists() == true) { resourceDescriptor.performAction(null, Action.DELETE); } } else { DefaultParameters updateStyle = DefaultParameters.MODIFY_REPLACE; if(isNew()) { updateStyle = DefaultParameters.NEW; } ResourceParameterBuilder parameterBuilder = new ResourceParameterBuilder(); parameterBuilder.addAll(resourceParameters); parameterBuilder.addParameter(updateStyle, "true"); resourceDescriptor.writeXML(variableContainer, content,parameterBuilder.getParameters()); } setContentMetatData(resourceDescriptor.getResourceMetaData(null)); } setResourceAttribute("new",false+""); setResourceAttribute("modified",false+""); CNodeList children = (CNodeList) getChildNodes(); for (Node node : children) { if(node instanceof ResourceElement) { ((ResourceElement) node).update(variableContainer,callingControlElement,resourceParameters); } } } public boolean isNew() { return getResourceAttribute("new").equals("true"); } public void setNew(boolean isNew) { setResourceAttribute("new",isNew+""); } public boolean isModified() { return getResourceAttribute("modified").equals("true"); } public void setModified(boolean modified) { setResourceAttribute("modified",modified+""); } public void setResourceDescriptor(ResourceDescriptor resourceDescriptor) { this.resourceDescriptor = resourceDescriptor; } // public ResourceElement(ResourceNode parentNode, ResourceControlElement resourceControlElement) throws Exception // { // this.parentNode = parentNode; // this.resourceControlElement = resourceControlElement; // this.recursive = false; // namespaceURI = parentNode.getNamespaceURI(); // prefix = parentNode.getPrefix(); // NamedNodeMap attributeNamedNodeMap = resourceControlElement.getControlElementDeclaration().getAttributes(); // for(int index = 0; index < attributeNamedNodeMap.getLength(); index++) // { // Attr attr = (Attr) attributeNamedNodeMap.item(index); // ResourceAttr resourceAttr = new ResourceAttr(this,attr.getNodeName(), attr.getNodeValue()); // attributeList.add(resourceAttr); // } // // if(attributeList.getNamedItem("name") != null) // { // localName = attributeList.getNamedItem("name").getNodeValue(); // } // else // { // localName = resourceControlElement.getControlElementDeclaration().getLocalName(); // } // // //if we have a URI, then we can go ahead a load a resourceDescriptor for this element // if(attributeList.getNamedItem("uri") != null) // { // this.resourceDescriptor = CapoApplication.getDataManager().getResourceDescriptor(resourceControlElement, attributeList.getNamedItem("uri").getNodeValue()); // // this.resourceControlElement.setResourceDescriptor(resourceDescriptor); // } // else if(attributeList.getNamedItem("path") != null) //check for a path attribute, and ask our parent to load us // { // this.resourceDescriptor = parentNode.getResourceDescriptor().getChildResourceDescriptor(resourceControlElement, attributeList.getNamedItem("path").getNodeValue()); // } // else // { // //we don't have anything, throw an exception for now? // throw new Exception("Must have a uri or a path attribute"); // } // // //sometimes we may have variables that need to be filled out laster, so we can't init or open this yet. // if(resourceControlElement.getControlElementDeclaration().getAttribute("dynamic").equalsIgnoreCase("true") == false) // { // resourceDescriptor.init(this,resourceControlElement.getParentGroup(), LifeCycle.EXPLICIT,true,ResourceParameterBuilder.getResourceParameters(resourceControlElement.getControlElementDeclaration())); // resourceDescriptor.open(resourceControlElement.getParentGroup(), ResourceParameterBuilder.getResourceParameters(resourceControlElement.getControlElementDeclaration())); // } // // NodeList childResourceElementDeclarationNodeList = XPath.selectNSNodes(resourceControlElement.getControlElementDeclaration(), prefix+":child", prefix+"="+namespaceURI); // for(int index = 0; index < childResourceElementDeclarationNodeList.getLength(); index++) // { // ResourceControlElement childResourceControlElement = new ResourceControlElement(); // //XXX This is a hack! we are setting the parent group to null, so that it won't process any of the attributes that might have vars. // childResourceControlElement.init((Element) childResourceElementDeclarationNodeList.item(index), resourceControlElement, null, resourceControlElement.getControllerClientRequestProcessor()); // //XXX then we set it back here, so the we still have the full var stack. This would all be fine until we change the init method in the AbstractControl class. // childResourceControlElement.setParentGroup(resourceControlElement.getParentGroup()); // nodeList.add(new ResourceElement(this, childResourceControlElement)); // } // } public void setContent(CElement content) { this.content = content; if(content != null) { this.content.addCDOMEventListener(this); content.setParent(this); } } public Element getContent() { return content; } @Override public ResourceDescriptor getResourceDescriptor() { return new ResourceElementResourceDescriptor(this); } @Override public ResourceDescriptor getProxyedResourceDescriptor() { return this.resourceDescriptor; } @Override public ResourceControlElement getResourceControlElement() { return this.ownerResourceDocument.getResourceControlElement(); } @Override public String getNodeName() { if(isContainter() == false && content != null && ownerResourceDocument.isFullDocument() == false) { return content.getNodeName(); } else { return super.getNodeName(); } } @Override public NodeList getChildNodes() { //depending on how we're created, we either know the list, or we want to figure it out. if (dynamic == false) { if(isContainter() == true) { return super.getChildNodes(); } else //were a leaf, and we should return our content, and we should pretend that our content's root element is us, and we don't have any children { CNodeList tempNodeList = new CNodeList(); tempNodeList.addAll(content.getChildNodes()); // if(ownerResourceDocument.isFullDocument()) // { tempNodeList.addAll(super.getChildNodes()); //} return tempNodeList; } } if (childResourceContentMetaData == null) { childResourceContentMetaData = contentMetaData.getContainedResources(); for (ContentMetaData childContentMetaData : childResourceContentMetaData) { try { appendChild(new ResourceElement(ownerResourceDocument,this,CapoApplication.getDataManager().getResourceDescriptor(null, childContentMetaData.getResourceURI().getBaseURI()))); } catch (Exception e) { CapoApplication.logger.log(Level.WARNING,"couldn't load resource: "+childContentMetaData.getResourceURI(),e); } } if (contentMetaData.isContainer() == false && ownerResourceDocument.isFullDocument()) { if (contentMetaData.getContentFormatType() == ContentFormatType.XML) { try { resourceDescriptor.open(null); Element xmlElement = resourceDescriptor.readXML(null); resourceDescriptor.close(null); appendChild(xmlElement); } catch (Exception e) { CapoApplication.logger.log(Level.WARNING,"couldn't load resource data: "+contentMetaData.getResourceURI(),e); } } else { //XXX this is incomplete!!! } } } return super.getChildNodes(); } @Override public Node getFirstChild() { NodeList childNodes = getChildNodes(); if (childNodes.getLength() > 0) { return childNodes.item(0); } else { return null; } } @Override public Node getNextSibling() { NodeList siblingList = getParentNode().getChildNodes(); int myPosition = 0; for(int index = 0; index < siblingList.getLength(); index++) { Node siblingNode = siblingList.item(index); if (siblingNode.isSameNode(this)) { myPosition = index; break; } } if (myPosition+1 < siblingList.getLength()) { return siblingList.item(myPosition+1); } else { return null; } } @Override public NamedNodeMap getAttributes() { if(ownerResourceDocument.isFullDocument() || ownerResourceDocument.isIncludeAttributes()) { return super.getAttributes(); } else if(isContainter() == true ) { return new CNamedNodeMap(); } else if (content != null) { return content.getAttributes(); } else { return new CNamedNodeMap(); } } public ResourceDocument getOwnerResourceDocument() { return ownerResourceDocument; } @Override public boolean hasChildNodes() { return getChildNodes().getLength() > 0; } public void postClone(Object parentObject, Object clonedObject) { ResourceElement clonedResourceElement = (ResourceElement) clonedObject; //we treat these differently, because we don't want them to recurse clonedResourceElement.ownerResourceDocument = ownerResourceDocument; super.postClone(parentObject, clonedObject); if (clonedResourceElement.content != null) { clonedResourceElement.content.addCDOMEventListener(clonedResourceElement); } } @Override public String getNamespaceURI() { if(isContainter() == false && content != null && ownerResourceDocument.isFullDocument() == false) { return content.getNamespaceURI(); } else { return super.getNamespaceURI(); } } @Override public String getLocalName() { if(isContainter() == false && content != null && ownerResourceDocument.isFullDocument() == false) { return content.getLocalName(); } else { return super.getLocalName(); } } @Override public Node appendChild(Node newChild) throws DOMException { if(newChild instanceof ResourceElement == false) { SimpleContentMetaData metaData = new SimpleContentMetaData(contentMetaData.getResourceURI()); ResourceElement childResourceElement = new ResourceElement(getOwnerResourceDocument(), newChild.getLocalName(), (CElement) newChild, metaData); childResourceElement.setNew(true); childResourceElement.setModified(true); return super.appendChild(childResourceElement); } return super.appendChild(newChild); } @Override public Node removeChild(Node oldChild) throws DOMException { if(oldChild instanceof ResourceElement == false) { content = null; setModified(true); return oldChild; } return super.removeChild(oldChild); } @Override public String getAttribute(String name) { if (hasAttribute(name)) { return getAttributes().getNamedItem(name).getNodeValue(); } else { return ""; } } public Element export(boolean contentOnly) throws Exception { return ResourceDocument.export(this,contentOnly).getDocumentElement(); } /** * Will always set a ResourceElements real attributes, as opposed to it's content's * @param name * @param value */ public void setResourceAttribute(String name, String value) { attributeList.setNamedItemNS(new CAttr(this, null, name, value)); } public String getResourceAttribute(String name) { if (attributeList.getNamedItem(name) == null) { return ""; } else { return attributeList.getNamedItem(name).getNodeValue(); } } public CAttr setResourceAttributeNode(CAttr attr) { attributeList.setNamedItem(attr); return attr; } }