/*******************************************************************************
* 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.project.capabilities;
import java.io.*;
import org.w3c.dom.*;
import org.jboss.tools.common.meta.XAttribute;
import org.jboss.tools.common.meta.action.impl.handlers.DefaultCreateHandler;
import org.jboss.tools.common.model.*;
import org.jboss.tools.common.model.engines.impl.EnginesLoader;
import org.jboss.tools.common.model.loaders.XObjectLoader;
import org.jboss.tools.common.model.loaders.impl.SerializingLoader;
import org.jboss.tools.common.model.util.*;
import org.jboss.tools.common.xml.*;
import org.jboss.tools.jsf.messages.JSFUIMessages;
public class FileAdditionPerformer extends PerformerItem {
XModelObject fileAddition;
XModelObject configFile;
String xPath;
String preferredPosition;
String text;
Element element;
XModelObject targetObject;
String targetAttribute;
String attributePath;
XModelObject updateObject = null;
String attributeValue = null;
public String getDisplayName() {
return fileAddition.getAttributeValue("label");
}
public void init(XModelObject configFile, XModelObject fileAddition) {
this.fileAddition = fileAddition;
this.configFile = configFile;
xPath = fileAddition.getAttributeValue("x-path");
preferredPosition = fileAddition.getAttributeValue("preferred position");
text = fileAddition.getAttributeValue("text");
targetObject = configFile;
}
void setConfigFile(XModelObject configFile) {
this.configFile = configFile;
targetObject = configFile;
}
public boolean check() {
if(!isSelected()) return true;
if(!scan(configFile, "")) {
String path = XModelObjectLoaderUtil.getResourcePath(configFile);
String message = "Cannot find x-path " + xPath + " in config file" + path + ".\n"
+ "Please correct file addition " + fileAddition.getAttributeValue("label") + ".";
report(message);
return false;
}
if(!parseText()) return false;
return true;
}
public boolean execute(PerformerContext context) throws XModelException {
if(!isSelected()) return true;
if(targetAttribute != null && attributeValue != null) {
targetObject.getModel().editObjectAttribute(targetObject, targetAttribute, attributeValue);
} else if(updateObject != null) {
mergeAttributes(targetObject, updateObject);
mergeChildren(targetObject, updateObject.getChildren());
}
String capability = fileAddition.getParent().getAttributeValue("name");
context.changeList.add("" + capability + ": " + "Added \"" + getDisplayName() + "\" to " + fileAddition.getAttributeValue("file name"));
context.monitor.worked(1);
return true;
}
private boolean scan(XModelObject object, String xp) {
String xml = object.getModelEntity().getXMLSubPath();
if(xml == null || xml.length() == 0) {
return scanChildren(object, xp);
}
xp += "/" + xml;
if(!xPath.startsWith(xp)) return false;
if(xPath.equals(xp)) {
targetObject = object;
targetAttribute = null;
return true;
}
if(scanAttributes(object, xp)) return true;
return scanChildren(object, xp);
}
private boolean scanAttributes(XModelObject object, String xp) {
XAttribute[] as = object.getModelEntity().getAttributes();
for (int i = 0; i < as.length; i++) {
String xml = as[i].getXMLName();
if(xml == null || xml.length() == 0) continue;
xml = xml.replace('.', '/');
if(xml.endsWith("#text")) {
xml = xml.substring(0, xml.length() - 5) + "text()";
} else {
int k = xml.lastIndexOf("/");
if(k < 0) xml = "@" + xml; else xml = xml.substring(0, k + 1) + "@" + xml.substring(k + 1);
}
xp = xp + "/" + xml;
if(xp.equals(xPath) || xp.startsWith(xPath)) {
targetObject = object;
targetAttribute = as[i].getName();
attributePath = null;
if(!xp.equals(xPath)) {
attributePath = xp.substring(xPath.length() + 1);
attributePath = attributePath.replace('/', '.');
if(attributePath.endsWith("text()")) {
attributePath = attributePath.substring(0, attributePath.length() - 6) + "#text";
}
}
return true;
}
}
return false;
}
private boolean scanChildren(XModelObject object, String xp) {
XModelObject[] cs = object.getChildrenForSave();
for (int i = 0; i < cs.length; i++) {
if(scan(cs[i], xp)) return true;
}
return false;
}
private boolean parseText() {
if(text == null) return false;
if(text.length() == 0) return true;
if(text.trim().startsWith("<") || targetAttribute == null) {
String tag = targetObject.getModelEntity().getXMLSubPath();
String body = "<" + tag + ">\n" + text + "</" + tag + ">\n";
element = XMLUtilities.getElement(new StringReader(body), XMLEntityResolver.getInstance());
if(element == null) {
String[] errors = XMLUtilities.getXMLErrors(new StringReader(body), false, XMLEntityResolver.getInstance());
String message = "Cannot load xml";
if(errors.length > 0) message += ": " + errors[0];
message += "\nPlease correct file addition " + fileAddition.getAttributeValue("label") + ".";
report(message);
return false;
}
if(targetAttribute == null) {
updateObject = XModelObjectLoaderUtil.createValidObject(targetObject.getModel(), targetObject.getModelEntity().getName());
XObjectLoader loader = XModelObjectLoaderUtil.getObjectLoader(configFile);
if(loader instanceof SerializingLoader) {
SerializingLoader sl = (SerializingLoader)loader;
sl.loadFragment(updateObject, element);
} else {
new XModelObjectLoaderUtil().load(element, updateObject);
}
} else {
attributeValue = readAttributeValue(element);
}
} else {
attributeValue = text;
}
return true;
}
private void report(String message) {
ServiceDialog d = configFile.getModel().getService();
d.showDialog(JSFUIMessages.ERROR, message, new String[]{JSFUIMessages.CLOSE}, null, ServiceDialog.ERROR);
}
private String readAttributeValue(Element element) {
XModelObjectLoaderUtil util = new XModelObjectLoaderUtil();
if(attributePath != null) {
return util.getAttribute(element, attributePath);
} else {
return XMLUtilities.getCDATA(element);
}
}
private void mergeAttributes(XModelObject object, XModelObject update) throws XModelException {
XAttribute[] as = update.getModelEntity().getAttributes();
for (int i = 0; i < as.length; i++) {
String xml = as[i].getXMLName();
if(xml == null || xml.indexOf('.') < 0) continue;
String v = update.getAttributeValue(as[i].getName());
if(v == null || v.length() == 0) continue;
object.getModel().editObjectAttribute(object, as[i].getName(), v);
}
}
private void mergeChildren(XModelObject object, XModelObject[] update) throws XModelException {
for (int i = 0; i < update.length; i++) {
String pp = update[i].getPathPart();
XModelObject c = object.getChildByPath(pp);
if(c == null) {
DefaultCreateHandler.addCreatedObject(object, update[i], -1);
if("0".equals(preferredPosition) || "top".equals(preferredPosition)) {
moveToPotition(object, update[i], 0);
}
} else {
String xml = update[i].getModelEntity().getXMLSubPath();
if(xml == null || xml.length() == 0) {
mergeChildren(c, update[i].getChildren());
} else {
EnginesLoader.merge(c, update[i], true);
}
}
}
}
private void moveToPotition(XModelObject parent, XModelObject child, int pos) {
if(!(parent instanceof XOrderedObject)) return;
XModelObject[] cs = parent.getChildren();
for (int i = 0; i < cs.length; i++) {
if(cs[i] != child) continue;
if(i == 0) return;
((XOrderedObject)parent).move(i, 0, true);
return;
}
}
}