/* * 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 java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Stack; import org.seasar.mayaa.cycle.CycleWriter; import org.seasar.mayaa.engine.Page; import org.seasar.mayaa.engine.processor.ChildEvaluationProcessor; import org.seasar.mayaa.engine.processor.InformalPropertyAcceptable; import org.seasar.mayaa.engine.processor.ProcessStatus; import org.seasar.mayaa.engine.processor.ProcessorProperty; import org.seasar.mayaa.engine.specification.PrefixAwareName; import org.seasar.mayaa.impl.cycle.CycleUtil; import org.seasar.mayaa.impl.cycle.DefaultCycleLocalInstantiator; import org.seasar.mayaa.impl.util.collection.NullIterator; /** * @author Masataka Kurihara (Gluegent, Inc.) */ public abstract class AbstractAttributableProcessor extends TemplateProcessorSupport implements ChildEvaluationProcessor, InformalPropertyAcceptable { private static final long serialVersionUID = -1406205460425148574L; private boolean _childEvaluation; private List/*<Serializable(ProcessorProperty or PrefixAwareName)>*/ _attributes; private static final String PROCESS_TIME_INFO_KEY = AbstractAttributableProcessor.class.getName() + "#processTimeInfo"; static { CycleUtil.registVariableFactory(PROCESS_TIME_INFO_KEY, new DefaultCycleLocalInstantiator() { public Object create(Object owner, Object[] params) { return new Stack/*<ProcesstimeInfo>*/(); } }); } private void clearProcesstimeInfo() { CycleUtil.clearLocalVariable(PROCESS_TIME_INFO_KEY, this); } protected void prepareProcesstimeInfo() { Stack piStack = (Stack) CycleUtil.getLocalVariable( PROCESS_TIME_INFO_KEY, this, null); if (piStack.size() == 0) { piStack.push(new ProcesstimeInfo()); } } protected ProcesstimeInfo pushProcesstimeInfo() { Stack piStack = (Stack) CycleUtil.getLocalVariable( PROCESS_TIME_INFO_KEY, this, null); return (ProcesstimeInfo) piStack.push(new ProcesstimeInfo()); } protected ProcesstimeInfo peekProcesstimeInfo() { return (ProcesstimeInfo) ((Stack) CycleUtil.getLocalVariable( PROCESS_TIME_INFO_KEY, this, null)).peek(); } protected ProcesstimeInfo popProcesstimeInfo() { Stack piStack = (Stack) CycleUtil.getLocalVariable( PROCESS_TIME_INFO_KEY, this, null); return (ProcesstimeInfo) piStack.pop(); } // MLD property public void setChildEvaluation(boolean childEvaluation) { _childEvaluation = childEvaluation; } // MLD method public void addInformalProperty(PrefixAwareName name, Serializable attr) { if (_attributes == null) { _attributes = new ArrayList(); } _attributes.add(attr); } /** * @deprecated 1.1.9 代わりに{@link #getInformalPropertyClass()}を使う */ public Class getPropertyClass() { return getInformalPropertyClass(); } /** * @deprecated 1.1.9 代わりに{@link #getInformalPropertyClass()}を使う */ public Class getExpectedClass() { return getInformalExpectedClass(); } public Class getInformalPropertyClass() { return ProcessorProperty.class; } public Class getInformalExpectedClass() { return Object.class; } public Iterator iterateInformalProperties() { if (_attributes == null) { return NullIterator.getInstance(); } return _attributes.iterator(); } // processtime method public void addProcesstimeProperty(ProcessorProperty prop) { if (prop == null) { throw new IllegalArgumentException(); } prepareProcesstimeInfo(); ProcesstimeInfo info = peekProcesstimeInfo(); info.addProcesstimeProperty(prop); } public boolean hasProcesstimeProperty(ProcessorProperty prop) { if (prop == null) { throw new IllegalArgumentException(); } prepareProcesstimeInfo(); ProcesstimeInfo info = peekProcesstimeInfo(); return info.hasProcesstimeProperty(prop); } public Iterator iterateProcesstimeProperties() { prepareProcesstimeInfo(); ProcesstimeInfo info = peekProcesstimeInfo(); return info.iterateProcesstimeProperties(); } protected abstract ProcessStatus writeStartElement(); protected abstract void writeBody(String body); protected abstract void writeEndElement(); /** * このメソッドをoverrideしないこと。 * 代わりに{@link #processStart(Page)}をoverrideすること。 */ public ProcessStatus doStartProcess(Page topLevelPage) { if (_childEvaluation) { prepareProcesstimeInfo(); pushProcesstimeInfo(); } return processStart(topLevelPage); } /** * 子クラスはdoStartProcessではなくこのメソッドをoverrideすること。 * ProcesstimeInfoを取得するには{@link #peekProcesstimeInfo()}を使用します。 * * @param topLevelPage 描画トップレベルのページ。 * @return 子プロセッサを処理する場合にはEVAL_BODY_INCLUDE、 * 子プロセッサの処理をスキップする場合にはSKIP_BODYを返す。 * ({@link #writeStartElement()}を呼ぶ) */ protected ProcessStatus processStart(Page topLevelPage) { if (_childEvaluation) { return ProcessStatus.EVAL_BODY_BUFFERED; } return writeStartElement(); } public boolean isChildEvaluation() { return _childEvaluation; } public void setBodyContent(CycleWriter body) { if (_childEvaluation) { if (body == null) { throw new IllegalArgumentException(); } ProcesstimeInfo info = peekProcesstimeInfo(); info.setBody(body); } } public void doInitChildProcess() { // do nothing. } public boolean isIteration() { return false; } public ProcessStatus doAfterChildProcess() { return ProcessStatus.SKIP_BODY; } /** * このメソッドをoverrideしないこと。 * 代わりに{@link #processEnd()}をoverrideすること。 */ public ProcessStatus doEndProcess() { try { return processEnd(); } finally { if (_childEvaluation) { popProcesstimeInfo(); } } } /** * 子クラスはdoEndProcessではなくこのメソッドをoverrideすること。 * ProcesstimeInfoを取得するには{@link #peekProcesstimeInfo()}を使用します。 * * @return ページのこのタグ以降を処理する場合にはEVAL_PAGE、 * 以降の処理をスキップする場合にはSKIP_PAGE。 */ protected ProcessStatus processEnd() { if (_childEvaluation) { writeStartElement(); ProcesstimeInfo info = peekProcesstimeInfo(); CycleWriter body = info.getBody(); if (body != null) { writeBody(body.getString()); } } writeEndElement(); return ProcessStatus.EVAL_PAGE; } // for serialize private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { in.defaultReadObject(); clearProcesstimeInfo(); } //helper class, methods ---------------------------------------- protected static class ProcesstimeInfo { private CycleWriter _body; private List _processtimeProperties; public void setBody(CycleWriter body) { if (body == null) { throw new IllegalArgumentException(); } _body = body; } public CycleWriter getBody() { return _body; } public boolean hasProcesstimeProperty(ProcessorProperty property) { if (property == null) { throw new IllegalArgumentException(); } if (_processtimeProperties == null) { return false; } return _processtimeProperties.contains(property); } public void addProcesstimeProperty(ProcessorProperty property) { if (property == null) { throw new IllegalArgumentException(); } if (_processtimeProperties == null) { _processtimeProperties = new ArrayList(); } if (_processtimeProperties.contains(property) == false) { _processtimeProperties.add(property); } } public Iterator iterateProcesstimeProperties() { if (_processtimeProperties == null) { return NullIterator.getInstance(); } return _processtimeProperties.iterator(); } } }