/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.jsf.model;
import java.io.*;
import java.util.Set;
import org.w3c.dom.*;
import org.jboss.tools.common.meta.XAttribute;
import org.jboss.tools.common.meta.XModelEntity;
import org.jboss.tools.common.model.*;
import org.jboss.tools.common.model.filesystems.*;
import org.jboss.tools.common.model.filesystems.impl.*;
import org.jboss.tools.common.model.loaders.impl.SimpleWebFileLoader;
import org.jboss.tools.common.model.util.*;
import org.jboss.tools.common.xml.XMLUtilities;
import org.jboss.tools.jsf.JSFModelPlugin;
import org.jboss.tools.jst.web.model.*;
public class FacesConfigLoader extends AbstractWebDiagramLoader implements WebProcessLoader, JSFConstants {
public static String AUXILIARY_FILE_EXTENSION = "jsfdia"; //$NON-NLS-1$
protected FileAuxiliary createFileAuxiliary() {
return new FileAuxiliary(AUXILIARY_FILE_EXTENSION, false);
}
protected XModelObjectLoaderUtil createUtil() {
return new SFUtil();
}
public void load(XModelObject object) {
// String entity = object.getModelEntity().getName();
String body = XModelObjectLoaderUtil.getTempBody(object);
int resolution = EntityXMLRegistration.getInstance().resolve(object.getModelEntity());
if(EntityXMLRegistration.isSystemId(body)) resolution = EntityXMLRegistration.UNRESOLVED;
String[] errors =
XMLUtil.getXMLErrors(new StringReader(body), resolution == EntityXMLRegistration.DTD, resolution == EntityXMLRegistration.SCHEMA);
boolean hasErrors = (errors != null && errors.length > 0);
if(hasErrors) {
object.setAttributeValue("isIncorrect", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
object.setAttributeValue("incorrectBody", body); //$NON-NLS-1$
object.set("actualBodyTimeStamp", "-1"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
object.setAttributeValue("isIncorrect", "no"); //$NON-NLS-1$ //$NON-NLS-2$
object.set("correctBody", body); //$NON-NLS-1$
object.set("actualBodyTimeStamp", "0"); //$NON-NLS-1$ //$NON-NLS-2$
object.setAttributeValue("incorrectBody", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
Document doc = XMLUtil.getDocument(new StringReader(body));
if(doc == null) {
XModelObjectLoaderUtil.addRequiredChildren(object);
return;
}
Element element = doc.getDocumentElement();
util.load(element, object);
((FileFacesConfigImpl)object).updateRuleIndices();
setEncoding(object, body);
if(object.getModelEntity().getAttribute("systemId") != null) { //$NON-NLS-1$
NodeList nl = doc.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if(n instanceof DocumentType) {
DocumentType dt = (DocumentType)n;
object.setAttributeValue("systemId", dt.getSystemId()); //$NON-NLS-1$
if(dt.getPublicId() == null) {
object.setAttributeValue("publicId", "null"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
String loadingError = util.getError();
reloadProcess(object);
object.set("actualBodyTimeStamp", "" + object.getTimeStamp()); //$NON-NLS-1$ //$NON-NLS-2$
((AbstractXMLFileImpl)object).setLoaderError(loadingError);
if(!hasErrors && loadingError != null) {
object.setAttributeValue("isIncorrect", "yes"); //$NON-NLS-1$ //$NON-NLS-2$
object.setAttributeValue("incorrectBody", body); //$NON-NLS-1$
object.set("actualBodyTimeStamp", "" + object.getTimeStamp()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public void reloadProcess(XModelObject object) {
FacesProcessImpl process = (FacesProcessImpl)object.getChildByPath(ELM_PROCESS);
if(process == null) return;
process.setReference(object);
if(!object.isActive()) return;
String bodyAux = (object.getParent() == null ? null : aux.read(object.getParent(), object));
if (bodyAux != null) {
Document doc2 = XMLUtil.getDocument(new StringReader(bodyAux));
if (doc2 == null) {
//JSFModelPlugin.log("Unable to parse aux body of "+object.getPath());
} else {
util.load(doc2.getDocumentElement(), process);
}
}
process.setReference(null);
process.firePrepared();
}
public boolean saveLayout(XModelObject object) {
if(object == null || !object.isActive()) return false;
XModelObjectLoaderUtil util = new XModelObjectLoaderUtil();
try {
XModelObject process = object.getChildByPath(ELM_PROCESS);
if(process == null) return true;
process.setModified(true);
Element element = XMLUtil.createDocumentElement("PROCESS"); //$NON-NLS-1$
util.saveAttributes(element, process);
util.saveChildren(element, process);
StringWriter sw = new StringWriter();
XModelObjectLoaderUtil.serialize(element, sw);
XModelObjectLoaderUtil.setTempBody(process, sw.toString());
aux.write(object.getParent(), object, process);
return true;
} catch (IOException exc) {
JSFModelPlugin.getPluginLog().logError(exc);
return false;
}
}
public String serializeMainObject(XModelObject object) {
String entity = object.getModelEntity().getName();
String systemId = object.getAttributeValue("systemId"); //$NON-NLS-1$
String publicId = object.getAttributeValue("publicId"); //$NON-NLS-1$
if("null".equals(publicId)) publicId = null; //$NON-NLS-1$
if(systemId != null) {
int version = entity.equals(ENT_FACESCONFIG_11) ? 11 : 10;
if(systemId != null && systemId.length() == 0) systemId = (version == 10) ? DOC_EXTDTD : DOC_EXTDTD_11;
if(publicId != null && publicId.length() == 0) publicId = (version == 10) ? DOC_PUBLICID : DOC_PUBLICID_11;
}
Element element = (systemId == null && publicId == null)
? XMLUtil.createDocumentElement(object.getModelEntity().getXMLSubPath())
: XMLUtil.createDocumentElement(object.getModelEntity().getXMLSubPath(), DOC_QUALIFIEDNAME, publicId, systemId, null);
util.setup(null, false);
util.saveAttributes(element, object);
util.saveChildren(element, object);
util.saveFinalComment(element, object);
element.removeAttribute("NAME"); //$NON-NLS-1$
element.removeAttribute("EXTENSION"); //$NON-NLS-1$
try {
return SimpleWebFileLoader.serialize(element, object);
} catch (IOException e) {
JSFModelPlugin.getDefault().logError(e);
return null;
} catch (XModelException e) {
JSFModelPlugin.getDefault().logError(e);
return null;
}
}
}
class SFUtil extends XModelObjectLoaderUtil {
static String[] folders = new String[]{
JSFConstants.FOLDER_BEHAVIORS,
JSFConstants.FOLDER_COMPONENTS,
JSFConstants.FOLDER_CONVERTERS,
JSFConstants.FOLDER_MANAGED_BEANS,
JSFConstants.FOLDER_NAVIGATION_RULES,
JSFConstants.FOLDER_ORDERINGS,
JSFConstants.FOLDER_REFENCED_BEANS,
JSFConstants.FOLDER_RENDER_KITS,
JSFConstants.FOLDER_VALIDATORS,
JSFConstants.FOLDER_PROTECTED_VIEWS,
JSFConstants.FOLDER_FLOW_DEFINITIONS,
JSFConstants.FOLDER_EXTENSIONS};
protected Set<String> getAllowedChildren(XModelEntity entity) {
Set<String> children = super.getAllowedChildren(entity);
if("JSFManagedProperty".equals(entity.getName()) //$NON-NLS-1$
|| "JSFListEntries".equals(entity.getName()) //$NON-NLS-1$
|| "JSFMapEntry".equals(entity.getName())) { //$NON-NLS-1$
children.add("value"); //$NON-NLS-1$
children.add("null-value"); //$NON-NLS-1$
} else if("JSFNavigationCase".equals(entity.getName())) { //$NON-NLS-1$
// no 2.0 case
children.add("redirect"); //$NON-NLS-1$
}
if(entity.getAttribute("others") != null) {
children.add("others");
}
return children;
}
protected Set<String> getAllowedAttributes(XModelEntity entity) {
Set<String> attributes = super.getAllowedAttributes(entity);
return attributes;
}
public void loadChildren(Element element, XModelObject o) {
String entity = o.getModelEntity().getName();
if(o.getFileType() == XModelObject.FILE) {
super.loadChildren(element, o);
for (int i = 0; i < folders.length; i++) {
XModelObject c = o.getChildByPath(folders[i]);
if(c != null) super.loadChildren(element, c);
}
} else if("JSFManagedBean".equals(entity) || "JSFManagedBean20".equals(entity)) { //$NON-NLS-1$
loadManagedBeanChildren(element, o);
} else if("JSFManagedProperty".equals(entity)) { //$NON-NLS-1$
loadManagedPropertyChildren(element, o);
} else if("JSFListEntries".equals(entity)) { //$NON-NLS-1$
loadListEntriesChildren(element, o);
} else {
super.loadChildren(element, o);
if("JSFProtectedViews22".equals(entity)) {
XModelObject[] cs = o.getChildren();
if(cs.length > 0) {
//First child is loaded as an attribute
o.removeChild(cs[0]);
}
} else if("JSFContractMapping22".equals(entity)) {
XModelObject[] cs = o.getChildren("JSFURLPattern22");
if(cs.length > 0) {
//First child is loaded as an attribute
o.removeChild(cs[0]);
}
cs = o.getChildren("JSFContracts22");
if(cs.length > 0) {
//First child is loaded as an attribute
o.removeChild(cs[0]);
}
}
}
}
public boolean save(Element parent, XModelObject o) {
if(!needToSave(o)) return true;
return super.save(parent, o);
}
boolean needToSave(XModelObject o) {
if(o == null) return false;
String s = o.getModelEntity().getProperty("saveDefault"); //$NON-NLS-1$
if(!"false".equals(s)) return true; //$NON-NLS-1$
if(hasSetAttributes(o)) return true;
XModelObject[] cs = o.getChildren();
if(cs.length > 2) return true;
for (int i = 0; i < cs.length; i++) {
if(needToSave(cs[i])) return true;
}
return false;
}
private boolean hasSetAttributes(XModelObject o) {
XAttribute[] as = o.getModelEntity().getAttributes();
for (int i = 0; i < as.length; i++) {
String xml = as[i].getXMLName();
String v = o.getAttributeValue(as[i].getName());
if("others".equals(as[i].getName()) || "redirect".equals(as[i].getName())) { // 2.0 cases
if("true".equals(v)) return true;
}
// it would be more safe to check isSavable
if(xml == null || xml.length() == 0 || "NAME".equals(xml)) continue; //$NON-NLS-1$
if(v != null && v.length() > 0) return true;
}
String finalComment = o.get("#final-comment"); //$NON-NLS-1$
if(finalComment != null && finalComment.length() > 0) return true;
return false;
}
public boolean saveChildren(Element element, XModelObject o) {
String entity = o.getModelEntity().getName();
if(o.getFileType() == XModelObject.FILE) {
for (int i = 0; i < folders.length; i++) {
XModelObject c = o.getChildByPath(folders[i]);
if(c != null) super.saveChildren(element, c);
}
super.saveChildren(element, o);
return true;
} else if("JSFManagedBean".equals(entity) || "JSFManagedBean20".equals(entity)) { //$NON-NLS-1$
saveManagedBeanChildren(element, o);
return true;
} else if("JSFManagedProperty".equals(entity)) { //$NON-NLS-1$
saveManagedPropertyChildren(element, o);
return true;
} else if("JSFListEntries".equals(entity)) { //$NON-NLS-1$
saveListEntriesChildren(element, o);
return true;
} else {
boolean b = super.saveChildren(element, o);
if("true".equals(o.getAttributeValue("others"))) {
XMLUtilities.createElement(element, "others");
}
if("JSFContractMapping22".equals(entity)) {
NodeList list = element.getChildNodes();
boolean isWrong = false;
Node firstContract = null, secondContract = null;
for (int i = 0; i < list.getLength(); i++) {
Node n = list.item(i);
if(n.getNodeType() == Node.ELEMENT_NODE) {
if("contracts".equals(n.getNodeName())) {
if(firstContract == null)
firstContract = n;
else if(secondContract == null)
secondContract = n;
} else if("url-pattern".equals(n.getNodeName())) {
if(firstContract != null) isWrong = true;
}
}
}
if(isWrong) {
element.insertBefore(firstContract, secondContract);
}
} else if("JSFFlowDefinition22".equals(entity)) {
NodeList list = element.getChildNodes();
boolean isWrong = false;
Node initializer = null, finalizer = null, firstInboundParameter = null;
for (int i = 0; i < list.getLength(); i++) {
Node n = list.item(i);
if(n.getNodeType() == Node.ELEMENT_NODE) {
if("initializer".equals(n.getNodeName())) {
initializer = n;
} else if("finalizer".equals(n.getNodeName())) {
finalizer = n;
} else if("inbound-parameter".equals(n.getNodeName())) {
if(firstInboundParameter != null) firstInboundParameter = n;
} else if(initializer != null || finalizer != null) {
isWrong = true;
}
}
}
if(isWrong) {
if(initializer != null) {
element.insertBefore(initializer, firstInboundParameter);
}
if(finalizer != null) {
element.insertBefore(finalizer, firstInboundParameter);
}
}
} else if("JSFSwitch22".equals(entity)) {
NodeList list = element.getChildNodes();
boolean isWrong = false;
Node defaultOutcome = null;
for (int i = 0; i < list.getLength(); i++) {
Node n = list.item(i);
if(n.getNodeType() == Node.ELEMENT_NODE) {
if("default-outcome".equals(n.getNodeName())) {
defaultOutcome = n;
} else if("case".equals(n.getNodeName())) {
isWrong = true;
}
}
}
if(isWrong) {
element.insertBefore(defaultOutcome, null);
}
}
return b;
}
}
public void loadAttributes(Element element, XModelObject o) {
super.loadAttributes(element, o);
String entity = o.getModelEntity().getName();
if("JSFListEntry".equals(entity) || "JSFMapEntry".equals(entity)) { //$NON-NLS-1$ //$NON-NLS-2$
Element ce = XMLUtil.getUniqueChild(element, "null-value"); //$NON-NLS-1$
if(ce != null) {
o.setAttributeValue("null-value", "true"); //$NON-NLS-1$ //$NON-NLS-2$
o.setAttributeValue("value", ""); //$NON-NLS-1$ //$NON-NLS-2$
} else {
o.setAttributeValue("null-value", "false"); //$NON-NLS-1$ //$NON-NLS-2$
o.setAttributeValue("value", super.getAttribute(element, "value.#text")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
if(XMLUtilities.getUniqueChild(element, "others") != null) {
o.setAttributeValue("others", "true");
}
if(element.getNodeName().equals("redirect")) { // 2.0 case
o.setAttributeValue("redirect", "true");
}
}
protected boolean isSaveable(XModelEntity entity, String n, String v, String dv) {
if(v == null) return false;
if(v.length() == 0 || v.equals(dv)) {
XAttribute attr = entity.getAttribute(n);
return (attr != null && "always".equals(attr.getProperty("save"))); //$NON-NLS-1$ //$NON-NLS-2$
}
return super.isSaveable(entity, n, v, dv);
}
public String getAttribute(Element element, String xmlname, XAttribute attr) {
if("attribute-names".equals(xmlname)) //$NON-NLS-1$
return loadArray(element, "attribute-name"); //$NON-NLS-1$
if("redirect".equals(xmlname)) //$NON-NLS-1$
return (XMLUtil.getUniqueChild(element, "redirect") != null) ? "yes" : "no"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if("value.#text".equals(xmlname)) { //$NON-NLS-1$
if(XMLUtil.getUniqueChild(element, "null-value") != null) return "null-value"; //$NON-NLS-1$ //$NON-NLS-2$
}
return super.getAttribute(element, xmlname, attr);
}
public void saveAttribute(Element element, String xmlname, String value) {
if("redirect".equals(xmlname)) { //$NON-NLS-1$
if("yes".equals(value)) XMLUtil.createElement(element, "redirect"); //$NON-NLS-1$ //$NON-NLS-2$
} else if("value.#text".equals(xmlname) && "null-value".equals(value)) { //$NON-NLS-1$ //$NON-NLS-2$
XMLUtil.createElement(element, "null-value"); //$NON-NLS-1$
} else if("attribute-names".equals(xmlname)) { //$NON-NLS-1$
saveArray(element, "attribute-name", value); //$NON-NLS-1$
} else {
super.saveAttribute(element, xmlname, value);
}
}
public void saveAttributes(Element element, XModelObject o) {
super.saveAttributes(element, o);
String entity = o.getModelEntity().getName();
if("JSFConverter".equals(entity)) { //$NON-NLS-1$
eitherOr(element, "converter-for-class", "converter-id"); //$NON-NLS-1$ //$NON-NLS-2$
} else if("JSFListEntry".equals(entity) || "JSFMapEntry".equals(entity)) { //$NON-NLS-1$ //$NON-NLS-2$
if("true".equals(o.getAttributeValue("null-value"))) { //$NON-NLS-1$ //$NON-NLS-2$
XMLUtil.createElement(element, "null-value"); //$NON-NLS-1$
} else {
super.saveAttribute(element, "value.#text", o.getAttributeValue("value")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
void loadManagedBeanChildren(Element element, XModelObject o) {
Element ce = XMLUtil.getUniqueChild(element, "list-entries"); //$NON-NLS-1$
if(ce != null) {
o.setAttributeValue("content-kind", "list-entries"); //$NON-NLS-1$ //$NON-NLS-2$
XModelObject c = o.getChildByPath("Entries"); //$NON-NLS-1$
if(c != null) load(ce, c);
return;
}
ce = XMLUtil.getUniqueChild(element, "map-entries"); //$NON-NLS-1$
if(ce != null) {
o.setAttributeValue("content-kind", "map-entries"); //$NON-NLS-1$ //$NON-NLS-2$
XModelObject c = o.getChildByPath("Entries"); //$NON-NLS-1$
if(c != null) load(ce, c);
return;
}
o.setAttributeValue("content-kind", "properties"); //$NON-NLS-1$ //$NON-NLS-2$
super.loadChildren(element, o);
}
void loadManagedPropertyChildren(Element element, XModelObject o) {
Element ce = XMLUtil.getUniqueChild(element, "null-value"); //$NON-NLS-1$
if(ce != null) {
o.setAttributeValue("value-kind", "null-value"); //$NON-NLS-1$ //$NON-NLS-2$
o.setAttributeValue("value", ""); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
ce = XMLUtil.getUniqueChild(element, "list-entries"); //$NON-NLS-1$
if(ce != null) {
o.setAttributeValue("value-kind", "list-entries"); //$NON-NLS-1$ //$NON-NLS-2$
o.setAttributeValue("value", ""); //$NON-NLS-1$ //$NON-NLS-2$
XModelObject c = o.getChildByPath("Entries"); //$NON-NLS-1$
if(c != null) load(ce, c);
return;
}
ce = XMLUtil.getUniqueChild(element, "map-entries"); //$NON-NLS-1$
if(ce != null) {
o.setAttributeValue("value-kind", "map-entries"); //$NON-NLS-1$ //$NON-NLS-2$
o.setAttributeValue("value", ""); //$NON-NLS-1$ //$NON-NLS-2$
XModelObject c = o.getChildByPath("Entries"); //$NON-NLS-1$
if(c != null) load(ce, c);
return;
}
String v = getAttribute(element, "value.#text"); //$NON-NLS-1$
o.setAttributeValue("value-kind", "value"); //$NON-NLS-1$ //$NON-NLS-2$
o.setAttributeValue("value", v); //$NON-NLS-1$
}
void loadListEntriesChildren(Element element, XModelObject o) {
NodeList nl = element.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if(n.getNodeType() != Node.ELEMENT_NODE) continue;
String name = n.getNodeName();
if(!"null-value".equals(name) && !"value".equals(name)) continue; //$NON-NLS-1$ //$NON-NLS-2$
XModelObject c = o.getModel().createModelObject("JSFListEntry", null); //$NON-NLS-1$
if("null-value".equals(name)) { //$NON-NLS-1$
c.setAttributeValue("null-value", "true"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
c.setAttributeValue("null-value", "false"); //$NON-NLS-1$ //$NON-NLS-2$
c.setAttributeValue("value", getAttribute((Element)n, "#text")); //$NON-NLS-1$ //$NON-NLS-2$
}
o.addChild(c);
}
}
void saveManagedBeanChildren(Element element, XModelObject o) {
super.saveChildren(element, o);
}
void saveManagedPropertyChildren(Element element, XModelObject o) {
String kind = o.getAttributeValue("value-kind"); //$NON-NLS-1$
if("null-value".equals(kind)) { //$NON-NLS-1$
XMLUtil.createElement(element, "null-value"); //$NON-NLS-1$
} else if("value".equals(kind)) { //$NON-NLS-1$
super.saveAttribute(element, "value.#text", o.getAttributeValue("value")); //$NON-NLS-1$ //$NON-NLS-2$
} else {
XModelObject c = o.getChildByPath("Entries"); //$NON-NLS-1$
if(c != null) {
super.saveChildren(element, o);
} else {
XMLUtil.createElement(element, "null-value"); //$NON-NLS-1$
}
}
}
void saveListEntriesChildren(Element element, XModelObject o) {
XModelObject[] cs = o.getChildren();
for (int i = 0; i < cs.length; i++) {
boolean isNullValue = "true".equals(cs[i].getAttributeValue("null-value")); //$NON-NLS-1$ //$NON-NLS-2$
if(isNullValue) {
XMLUtil.createElement(element, "null-value"); //$NON-NLS-1$
} else {
Element ce = XMLUtil.createElement(element, "value"); //$NON-NLS-1$
saveAttribute(ce, "#text", cs[i].getAttributeValue("value")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}