void parseLang(Document doc, Locator locator, URL url, boolean addon)
throws Exception {
final Element root = doc.getRootElement();
final String lang = IDOMs.getRequiredElementValue(root, "language-name");
final LanguageDefinition langdef;
final Device device;
if (addon) {
if (log.debugable()) log.debug("Addon language to "+lang+" from "+root.getElementValue("addon-name", true));
langdef = LanguageDefinition.lookup(lang);
device = Devices.getDevice(langdef.getDeviceType());
if (root.getElement("case-insensitive") != null)
throw new UiException("case-insensitive not allowed in addon");
} else {
final String ns =
(String)IDOMs.getRequiredElementValue(root, "namespace");
final String deviceType =
(String)IDOMs.getRequiredElementValue(root, "device-type");
//if (log.debugable()) log.debug("Load language: "+lang+", "+ns);
PageRenderer pageRenderer = (PageRenderer)
locateClass(IDOMs.getRequiredElementValue(root, "renderer-class"))
.newInstance();
final List exts = parseExtensions(root);
if (exts.isEmpty())
throw new UiException("The extension must be specified for "+lang);
String ignoreCase = root.getElementValue("case-insensitive", true);
String bNative = root.getElementValue("native-namespace", true);
langdef = new LanguageDefinition(
deviceType, lang, ns, exts, pageRenderer,
"true".equals(ignoreCase), "true".equals(bNative), locator);
device = Devices.getDevice(deviceType);
}
parsePI(langdef, doc);
parseLabelTemplate(langdef, root);
parseDynamicTag(langdef, root);
parseMacroTemplate(langdef, root);
parseNativeTemplate(langdef, root);
for (Iterator it = root.getElements("library-property").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
final String nm = IDOMs.getRequiredElementValue(el, "name");
final String val = IDOMs.getRequiredElementValue(el, "value");
Library.setProperty(nm, val);
}
for (Iterator it = root.getElements("system-property").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
final String nm = IDOMs.getRequiredElementValue(el, "name");
final String val = IDOMs.getRequiredElementValue(el, "value");
System.setProperty(nm, val);
}
for (Iterator it = root.getElements("javascript").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
String src = el.getAttributeValue("src"),
pkg = el.getAttributeValue("package");
final boolean merge = "true".equals(el.getAttributeValue("merge"));
final boolean ondemand = "true".equals(el.getAttributeValue("ondemand"));
if (pkg != null) {
if (src != null)
log.warning("The src attribute ignored because package is specified, "+el.getLocator());
if (!ondemand && !merge) {
src = "~." + device.packageToPath(pkg);
pkg = null;
}
}
final String ctn = el.getText(true);
final JavaScript js;
if (pkg != null && pkg.length() > 0) {
if (ondemand) {
langdef.removeJavaScript("~." + device.packageToPath(pkg));
langdef.removeMergeJavaScriptPackage(pkg);
} else {
langdef.addMergeJavaScriptPackage(pkg);
}
continue; //TODO
} else if (src != null && src.length() > 0) {
if (ctn != null && ctn.length() > 0)
throw new UiException("You cannot specify the content if the src attribute is specified, "+el.getLocator());
final String charset = el.getAttributeValue("charset");
js = new JavaScript(src, charset);
} else if (ctn != null && ctn.length() > 0) {
js = new JavaScript(ctn);
} else {
log.warning("Ignored: none of the src or package attribute, or the content specified, "+el.getLocator());
continue;
}
langdef.addJavaScript(js);
}
for (Iterator it = root.getElements("javascript-module").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
langdef.addJavaScriptModule(
IDOMs.getRequiredAttributeValue(el, "name"),
IDOMs.getRequiredAttributeValue(el, "version"));
}
for (Iterator it = root.getElements("stylesheet").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
final String href = el.getAttributeValue("href");
final String ctn = el.getText(true);
final StyleSheet ss;
if (href != null && href.length() > 0) {
if (ctn != null && ctn.length() > 0)
throw new UiException("You cannot specify the content if the href attribute is specified, "+el.getLocator());
ss = new StyleSheet(href, el.getAttributeValue("type"), el.getAttributeValue("media"), false);
} else if (ctn != null && ctn.length() > 0) {
ss = new StyleSheet(ctn, el.getAttributeValue("type"), el.getAttributeValue("media"), true);
} else {
throw new UiException("You must specify either the href attribute or the content, "+el.getLocator());
}
langdef.addStyleSheet(ss);
}
for (Iterator it = root.getElements("zscript").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
final String zslang;
final Attribute attr = el.getAttributeItem("language");
if (attr == null) {
zslang = "Java";
} else {
zslang = attr.getValue();
if (zslang == null || zslang.length() == 0)
throw new UiException("The language attribute cannot be empty, "+attr.getLocator());
}
final String s = el.getText(true);
final String eachTime = el.getAttributeValue("each-time");
if ("true".equals(eachTime))
langdef.addEachTimeScript(zslang, s);
else
langdef.addInitScript(zslang, s);
}
for (Iterator it = root.getElements("component").iterator();
it.hasNext();) {
final Element el = (Element)it.next();
final String name =
IDOMs.getRequiredElementValue(el, "component-name");
String clsnm = el.getElementValue("component-class", true);
Class cls = null;
if (clsnm != null) {
if (clsnm.length() > 0) {
noEL("component-class", clsnm, el);
try {
cls = locateClass(clsnm);
} catch (Throwable ex) { //Feature 1873426
log.warning("Component "+name+" ignored. Reason: unable to load "+clsnm+" due to "
+ex.getClass().getName()+": "+ex.getMessage()
+(ex instanceof NoClassDefFoundError?"":"\n"+el.getLocator()));
log.debug(ex);
//keep processing (Feature 2060367)
}
} else {
clsnm = null;
}
}
final String macroURI = el.getElementValue("macro-uri", true);
final ComponentDefinitionImpl compdef;
if (macroURI != null && macroURI.length() != 0) {
if (log.finerable()) log.finer("macro component definition: "+name);
final String inline = el.getElementValue("inline", true);
compdef = (ComponentDefinitionImpl)
langdef.getMacroDefinition(
name, macroURI, "true".equals(inline), null);
if (cls != null)
compdef.setImplementationClass(cls);
else if (clsnm != null)
compdef.setImplementationClass(clsnm);
compdef.setDeclarationURL(url);
langdef.addComponentDefinition(compdef);
} else if (el.getElement("extends") != null) { //extends
final String extnm = el.getElementValue("extends", true);
if (log.finerable()) log.finer("Extends component definition, "+name+", from "+extnm);
final ComponentDefinition ref = langdef.getComponentDefinitionIfAny(extnm);
if (ref == null) {
log.warning("Component "+name+" ignored. Reason: extends a non-existent component "+extnm+".\n"+el.getLocator());
//not throw exception since the derived component might be
//ignored due to class-not-found
continue;
}
if (ref.isMacro())
throw new UiException("Unable to extend from a macro component, "+el.getLocator());
if (extnm.equals(name)) {
compdef = (ComponentDefinitionImpl)ref;
} else {
compdef = (ComponentDefinitionImpl)
ref.clone(ref.getLanguageDefinition(), name);
compdef.setDeclarationURL(url);
}
if (cls != null)
compdef.setImplementationClass(cls);
else if (clsnm != null)
compdef.setImplementationClass(clsnm);
langdef.addComponentDefinition(compdef);
//Note: setImplementationClass before addComponentDefinition
} else {
if (log.finerable()) log.finer("Add component definition: name="+name);
if (cls == null && clsnm == null)
throw new UiException("component-class is required, "+el.getLocator());
compdef = cls != null ?
new ComponentDefinitionImpl(langdef, null, name, cls):
new ComponentDefinitionImpl(langdef, null, name, clsnm);
compdef.setDeclarationURL(url);
langdef.addComponentDefinition(compdef);
}
String s = el.getElementValue("text-as", true);
if (s != null) { //empty means cleanup (for overriding)
noEL("text-as", s, el);
compdef.setTextAs(s);
}
s = el.getElementValue("preserve-blank", true);
if (s != null && !"false".equals(s))
compdef.setBlankPreserved(true);
String wgtnm = el.getElementValue("widget-class", true);
WidgetDefinition wgtdef = null;
if (wgtnm != null) {
if (!withEL(wgtnm))
wgtdef = getWidgetDefinition(langdef, compdef, wgtnm);
compdef.setDefaultWidgetClass(wgtnm);
}
s = el.getElementValue("component-apply", true);
if (s == null) s = el.getElementValue("apply", true); //backward-compatible
compdef.setApply(s);
for (Iterator i = el.getElements("mold").iterator(); i.hasNext();) {
final Element e = (Element)i.next();
final String nm = IDOMs.getRequiredElementValue(e, "mold-name");
final String moldURI = e.getElementValue("mold-uri", true);
String cssURI = e.getElementValue("css-uri", true);
final String wn = e.getElementValue("widget-class", true);
noEL("mold-uri", moldURI, e); //5.0 limitation
noEL("css-uri", cssURI, e);
compdef.addMold(nm, wn != null ? wn: wgtnm);
WidgetDefinition wd = wn == null ? wgtdef:
withEL(wn) ? null: getWidgetDefinition(langdef, compdef, wn);
if (moldURI != null) {
if (wd != null)
wd.addMold(nm, moldURI);
else
log.error("Mold "+nm+" for "+name+" ignored because "+
((wn != null && withEL(wn)) || (wgtnm != null && withEL(wgtnm)) ?
"widget-class contains EL expressions":"widget-class is required")
+", "+e.getLocator());
}
if (cssURI != null && cssURI.length() > 0) {
final char cc = cssURI.charAt(0);
if (cc != '/' && cc != '~') {
String n = wn != null ? wn: wgtnm;
if (!withEL(n)) {
int k = n.lastIndexOf('.');
cssURI = "~." + device.toAbsolutePath(
n.substring(0, k).replace('.', '/') + '/' + cssURI);
} else {
log.error("Absolute path required for cssURI, since the widget class contains EL expressions, "+e.getLocator());
}
}