/* * Copyright 2004-2012 the Seasar Foundation and the Others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.seasar.mayaa.impl.engine.processor; import org.seasar.mayaa.builder.PathAdjuster; import org.seasar.mayaa.cycle.script.CompiledScript; import org.seasar.mayaa.engine.Page; import org.seasar.mayaa.engine.processor.ProcessStatus; import org.seasar.mayaa.engine.processor.ProcessorProperty; import org.seasar.mayaa.engine.processor.ProcessorTreeWalker; import org.seasar.mayaa.engine.specification.PrefixAwareName; import org.seasar.mayaa.engine.specification.QName; import org.seasar.mayaa.impl.cycle.CycleUtil; import org.seasar.mayaa.impl.engine.EngineUtil; import org.seasar.mayaa.impl.engine.specification.SpecificationUtil; import org.seasar.mayaa.impl.provider.ProviderUtil; import org.seasar.mayaa.impl.util.StringUtil; /** * @author Masataka Kurihara (Gluegent, Inc.) */ public class AttributeProcessor extends TemplateProcessorSupport { private static final long serialVersionUID = 87560642282310502L; private PrefixAwareName _name; private ProcessorProperty _value; private ProcessorProperty _escapeAmp; protected AbstractAttributableProcessor findParentAttributable() { for (ProcessorTreeWalker parent = getParentProcessor(); parent != null; parent = parent.getParentProcessor()) { if (parent instanceof AbstractAttributableProcessor) { if (parent instanceof ElementProcessor) { // duplicated ElementProcessor is not attributable. if (((ElementProcessor) parent).isDuplicated()) { continue; } } return (AbstractAttributableProcessor) parent; } } throw new IllegalStateException("no attributable processor."); } // MLD property public void setName(PrefixAwareName name) { if (name == null) { throw new IllegalArgumentException(); } _name = name; } protected PrefixAwareName getName() { return _name; } // MLD property public void setValue(ProcessorProperty value) { if (value == null) { throw new IllegalArgumentException(); } _value = value; } // MLD property public void setEscapeAmp(ProcessorProperty escapeAmp) { ProcessorUtil.checkBoolableProperty(escapeAmp); _escapeAmp = escapeAmp; } boolean isEscapeAmp() { return ProcessorUtil.toBoolean(_escapeAmp); } /** * 親プロセッサの{@link QName}を返す。ただし * {@code parent}が{@link ElementProcessor}の場合にはそのnameを返す。 * @param parent 親プロセッサ * @return 親プロセッサの{@link QName}。 */ protected QName getParentQName(AbstractAttributableProcessor parent) { QName parentQName; if (parent.getClass() == ElementProcessor.class) { parentQName = ((ElementProcessor) parent).getName().getQName(); } else { parentQName = parent.getOriginalNode().getQName(); } return parentQName; } protected ProcessorProperty createProcessorProperty(PrefixAwareName name, ProcessorProperty value, String basePath) { return new ProcessorPropertyWrapper(_name, _value, basePath); } public ProcessStatus doStartProcess(Page topLevelPage) { /* 値なし属性もサポート(ただし非推奨のため、mayaa.mldのrequiredを外さない限りこの機能は無効。) if (_value == null) { throw new IllegalStateException(); } */ AbstractAttributableProcessor parent = findParentAttributable(); QName parentQName = getParentQName(parent); QName attributeQName = getName().getQName(); // 自動的にmayaaネームスペースを引き継いだだけであれば、親要素と同じにする。 if (getName().getPrefix().equals("") && parentQName.equals(getName().getQName()) == false) { attributeQName = SpecificationUtil.createQName( parentQName.getNamespaceURI(), attributeQName.getLocalName()); setName(SpecificationUtil.createPrefixAwareName(attributeQName, "")); } String basePath = null; PathAdjuster adjuster = ProviderUtil.getPathAdjuster(); if (adjuster.isTargetAttribute(parentQName, attributeQName)) { String contextPath = CycleUtil.getRequestScope().getContextPath(); String sourcePath = EngineUtil.getSourcePath(getStaticParentProcessor()); basePath = contextPath + sourcePath; } parent.addProcesstimeProperty(createProcessorProperty(_name, _value, basePath)); return ProcessStatus.SKIP_BODY; } // support class ------------------------------------------------ protected class ProcessorPropertyWrapper implements ProcessorProperty { private static final long serialVersionUID = 8190328285510500572L; private PrefixAwareName _attrName; private ProcessorProperty _attrValue; private CompiledScript _script; public ProcessorPropertyWrapper( PrefixAwareName name, ProcessorProperty property, String basePath) { if (name == null) { throw new IllegalArgumentException(); } _attrName = name; _attrValue = property; if (_attrValue != null) { if (_attrValue.getValue().isLiteral()) { _script = new EscapedLiteralScript(_attrValue.getValue(), basePath); } else { _script = new EscapableScript(_attrValue.getValue(), basePath); } } } public PrefixAwareName getName() { return _attrName; } public CompiledScript getValue() { return _script; } public boolean equals(Object obj) { if (obj instanceof ProcessorProperty) { PrefixAwareName otherName = ((ProcessorProperty) obj).getName(); return getName().getQName().equals(otherName.getQName()); } return false; } public int hashCode() { return toString().hashCode(); } public String toString() { if (_script == null) { return getName().toString() + "=null"; } return getName().toString() + "=\"" + _script + "\""; } } protected class EscapableScript extends ScriptWrapper { private static final long serialVersionUID = -5393294025521796857L; private String _basePath; public EscapableScript(CompiledScript script, String basePath) { super(script); _basePath = basePath; } public Object execute(Object[] args) { Object result = super.execute(args); if (isString() && StringUtil.hasValue(result)) { if (_basePath != null) { PathAdjuster adjuster = ProviderUtil.getPathAdjuster(); result = adjuster.adjustRelativePath(_basePath, result.toString()); } result = escape(result.toString()); } return result; } } protected class EscapedLiteralScript extends ScriptWrapper { private static final long serialVersionUID = -441522603771461865L; private String _escapedValue = ""; public EscapedLiteralScript(CompiledScript script, String basePath) { super(script); if (isString()) { Object obj = super.execute(null); if (StringUtil.hasValue(obj)) { _escapedValue = obj.toString(); if (basePath != null) { PathAdjuster adjuster = ProviderUtil.getPathAdjuster(); _escapedValue = adjuster.adjustRelativePath( basePath, _escapedValue); } _escapedValue = escape(_escapedValue); } } } public Object execute(Object[] args) { return _escapedValue; } } protected abstract class ScriptWrapper implements CompiledScript { private static final long serialVersionUID = -1582289477400400196L; private CompiledScript _script; private boolean _string; public ScriptWrapper(CompiledScript script) { _script = script; _string = String.class.equals(_script.getExpectedClass()); } public boolean isString() { return _string; } public void setExpectedClass(Class expectedClass) { _script.setExpectedClass(expectedClass); } public Class getExpectedClass() { return _script.getExpectedClass(); } public Object execute(Object[] args) { return _script.execute(args); } public void setMethodArgClasses(Class[] methodArgClasses) { _script.setMethodArgClasses(methodArgClasses); } public Class[] getMethodArgClasses() { return _script.getMethodArgClasses(); } public boolean isLiteral() { return _script.isLiteral(); } public String getScriptText() { return _script.getScriptText(); } public boolean isReadOnly() { return _script.isReadOnly(); } public void assignValue(Object value) { _script.assignValue(value); } public String toString() { return _script.toString(); } public String escape(String value) { if (isEscapeAmp()) { return StringUtil.escapeWhitespace(StringUtil.escapeXml(value)); } return StringUtil.escapeWhitespace(StringUtil.escapeXmlWithoutAmp(value)); } } }