/* * 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.builder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.seasar.mayaa.engine.Page; import org.seasar.mayaa.engine.Template; import org.seasar.mayaa.engine.specification.Specification; import org.seasar.mayaa.engine.specification.SpecificationNode; import org.seasar.mayaa.impl.engine.specification.SpecificationUtil; import org.seasar.mayaa.impl.source.SourceUtil; import org.seasar.mayaa.impl.util.ObjectUtil; import org.seasar.mayaa.impl.util.StringUtil; import org.seasar.mayaa.source.SourceDescriptor; /** * 対応するMayaaファイルにm:extends属性が存在しない場合、デフォルトのレイアウト * 設定をします。 * ページ名をパラメータ "defaultLayoutPageName" で "/foo/bar.html" の形式で * 指定します。 * また、パラメータ "generateMayaaNode" に true を指定すると、Mayaaファイルの * 無いテンプレートでもレイアウトが適用されるようにします。 * * @author Koji Suga (Gluegent Inc.) */ public class DefaultLayoutTemplateBuilder extends TemplateBuilderImpl { private static final Log LOG = LogFactory.getLog(DefaultLayoutTemplateBuilder.class); private static final long serialVersionUID = 6472968108941224353L; private static final String SYSTEM_ID_SUFFIX = ".mayaa/(auto)"; private String _defaultLayoutPageName; private boolean _generateMayaaNode; protected void afterBuild(Specification specification) { setupExtends((Template) specification); super.afterBuild(specification); } /** * TemplateBuilderImplの{@link #afterBuild(Specification)}を実行する前に、 * 必要ならm:extendsを自動生成します。 * * @param template 処理対象のテンプレート */ protected void setupExtends(Template template) { if (StringUtil.isEmpty(_defaultLayoutPageName)) { return; } if (_defaultLayoutPageName.equals(template.getSystemID())) { return; } Page page = template.getPage(); SpecificationNode mayaaNode = getMayaaNode(page); if (_generateMayaaNode && mayaaNode == null) { if (LOG.isDebugEnabled()) { LOG.debug("default layout - generate mayaa: " + page.getPageName()); } mayaaNode = createMayaaNode(page, template); if (template.getParentNode() != null) { mayaaNode.setParentNode(template.getParentNode()); template.setParentNode(mayaaNode); } page.addChildNode(mayaaNode); } if (mayaaNode != null) { addExtends(page, mayaaNode); } } /** * PageのMayaaノードを取得します。 * createMayaaNodeで自動生成したノードだった場合、そのノードは削除して * 再度Mayaaノードを取得します。 * * @param page ビルド対象のページ * @return 自動生成でないMayaaノード。無ければnullを返します。 */ protected SpecificationNode getMayaaNode(Page page) { SpecificationNode mayaaNode = SpecificationUtil.getMayaaNode(page); if (mayaaNode != null && mayaaNode.getSystemID().endsWith(SYSTEM_ID_SUFFIX)) { page.removeChildNode(mayaaNode); mayaaNode = SpecificationUtil.getMayaaNode(page); } return mayaaNode; } /** * ページ名に対応したMayaaファイルの代わりを作成します。 * * @param page Mayaaノードを作成するページ * @param specification sequenceIDを取得するためのspec * @return Mayaaノード */ protected SpecificationNode createMayaaNode( Page page, Specification specification) { String systemID = page.getPageName() + SYSTEM_ID_SUFFIX; return SpecificationUtil.createSpecificationNode( QM_MAYAA, systemID, 0, false, specification.nextSequenceID()); } /** * m:mayaa要素にm:extends属性を追加します。 * * @param page 処理中のページ * @param mayaaNode 属性を追加するm:mayaa要素 */ protected void addExtends(Page page, SpecificationNode mayaaNode) { String extendsValue = SpecificationUtil.getAttributeValue( mayaaNode, QM_EXTENDS); if (StringUtil.isEmpty(extendsValue)) { if (LOG.isDebugEnabled()) { LOG.debug("default layout - set extends: " + page.getPageName() + " m:extends=\"" + _defaultLayoutPageName + "\""); } mayaaNode.addAttribute(QM_EXTENDS, _defaultLayoutPageName); } } // Parameterizable implements ------------------------------------ public void setParameter(String name, String value) { if ("generateMayaaNode".equals(name)) { setGenerateMayaaNode(ObjectUtil.booleanValue(value, false)); } else if ("defaultLayoutPageName".equals(name)) { setDefaultLayoutPageName(value); } super.setParameter(name, value); } /** * @return the applyAllTemplates */ public boolean isGenerateMayaaNode() { return _generateMayaaNode; } /** * @param applyAllTemplates the applyAllTemplates to set */ public void setGenerateMayaaNode(boolean applyAllTemplates) { _generateMayaaNode = applyAllTemplates; } /** * @return the defaultLayoutPageName */ public String getDefaultLayoutPageName() { return _defaultLayoutPageName; } /** * @param defaultLayoutPageName the defaultLayoutPageName to set */ public void setDefaultLayoutPageName(String defaultLayoutPageName) { if (validatePageName(defaultLayoutPageName)) { _defaultLayoutPageName = defaultLayoutPageName; } } /** * デフォルトレイアウトとするページ名が正しいことを検証します。 * <ul> * <li>"/"始まりであること</li> * <li>"/../"などを含まないこと</li> * <li>ファイルが存在すること</li> * </ul> * * @param pageName 検証するページ名 * @return 正しければtrue */ protected boolean validatePageName(String pageName) { if (StringUtil.isEmpty(pageName)) { return false; } if (pageName.charAt(0) != '/' || pageName.indexOf("/../") != -1) { LOG.warn(StringUtil.getMessage( DefaultLayoutTemplateBuilder.class, 1, pageName)); return false; } SourceDescriptor source = SourceUtil.getSourceDescriptor(pageName); if (source == null || source.exists() == false) { LOG.warn(StringUtil.getMessage( DefaultLayoutTemplateBuilder.class, 2, pageName)); return false; } return true; } }