001/* 002 * (C) Copyright 2006-2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 */ 018 019package org.nuxeo.runtime.deployment.preprocessor.template; 020 021import java.util.LinkedHashMap; 022import java.util.Map; 023import java.util.regex.Matcher; 024import java.util.regex.Pattern; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028import org.nuxeo.common.utils.TextTemplate; 029 030/** 031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 032 */ 033public class Template { 034 035 private static final Log log = LogFactory.getLog(Template.class); 036 037 public static final String BEGIN = "BEGIN"; 038 039 public static final String END = "END"; 040 041 protected static final String JBOSS5_COMPAT = "org.nuxeo.runtme.preprocessing.jboss5"; 042 043 // we should use a linked hash map to preserve the 044 // insertion order when iterating over the elements in the map 045 final LinkedHashMap<String, Part> parts; 046 047 /** 048 * Must be removed when fixing deployment-fragment.xml files. 049 */ 050 protected boolean runningOnJBoss5 = false; 051 052 public Template() { 053 parts = new LinkedHashMap<>(); 054 // XXX compat code 055 String v = System.getProperty(JBOSS5_COMPAT); 056 if (v != null) { 057 runningOnJBoss5 = Boolean.parseBoolean(v); 058 } 059 } 060 061 public void addPart(String name, String text) { 062 parts.put(name, new Part(name, text)); 063 } 064 065 public void update(TemplateContribution tc, Map<String, String> ctx) { 066 String content = getContent(tc, ctx); 067 content = new TextTemplate(ctx).processText(content); 068 if (tc.isAppending()) { 069 appendText(tc.getMarker(), content); 070 } else if (tc.isPrepending()) { 071 prependText(tc.getMarker(), content); 072 } else if (tc.isReplacing()) { 073 replaceText(tc.getMarker(), content); 074 } 075 } 076 077 public void appendText(String marker, String text) { 078 Part part = parts.get(marker); 079 if (part != null) { 080 part.append(text); 081 } else { 082 log.debug("Could not find marker: " + marker); 083 } 084 } 085 086 public void prependText(String marker, String text) { 087 Part part = parts.get(marker); 088 if (part != null) { 089 part.prepend(text); 090 } else { 091 log.debug("Could not find marker: " + marker); 092 } 093 } 094 095 public void replaceText(String marker, String text) { 096 Part part = parts.get(marker); 097 if (part != null) { 098 part.replace(text); 099 } else { 100 log.debug("Could not find marker: " + marker); 101 } 102 } 103 104 public String getText() { 105 StringBuilder buf = new StringBuilder(); 106 for (Part part : parts.values()) { 107 buf.append(part.text); 108 } 109 return buf.toString(); 110 } 111 112 static class Part { 113 public final String name; // the name of the part used in markers 114 115 public final StringBuffer text; // the text before the marker 116 117 public final int offset; // the initial length of the text 118 119 Part(String name, String text) { 120 this.name = name; 121 this.text = text == null ? new StringBuffer() : new StringBuffer(text); 122 offset = this.text.length(); 123 } 124 125 public void append(String aText) { 126 text.append(aText); 127 } 128 129 public void prepend(String aText) { 130 text.insert(offset, aText); 131 } 132 133 public void replace(String aText) { 134 text.replace(offset, text.length(), aText); 135 } 136 137 public String getText() { 138 return text.toString(); 139 } 140 141 public String getName() { 142 return name; 143 } 144 145 } 146 147 /* 148 * TODO: Remove the following methods when deployment-fragment.xml files will be fixed. These files must not contain 149 * <module><java>...</java></module> declarations. 150 */ 151 152 /** 153 * Wrapper method introduced to fix JEE java modules in application template. XXX When this will be solved in trunk 154 * you can remove this method and simply call {@code tc.getContent();}. 155 */ 156 protected String getContent(TemplateContribution tc, Map<String, String> context) { 157 String content = tc.getContent(); 158 if (runningOnJBoss5 && "application".equals(tc.getTemplate()) && "MODULE".equals(tc.getMarker())) { 159 // remove JEE java modules 160 String oldcontent = content; 161 content = removeJavaModules(content); 162 if (oldcontent != content) { 163 log.warn("The deployment-fragment contains illegal JEE java module contribution: " 164 + context.get("bundle.shortName")); 165 } 166 if (content.length() == 0) { 167 return ""; 168 } 169 } 170 return "\n" + content.trim() + "\n"; 171 } 172 173 protected static final Pattern JAVA_MODULE = Pattern.compile("<\\s*module\\s*>\\s*<\\s*java\\s*>.+<\\s*/\\s*java\\s*>\\s*<\\s*/\\s*module\\s*>"); 174 175 /** 176 * Remove {@code <module><java>...</java></module>} from {@code application.xml} contributions. This a temporary fix 177 * to remove incorrect java module declarations from deployment-fragments - this should be fixed in each fragment. 178 */ 179 protected static String removeJavaModules(String content) { 180 Matcher m = JAVA_MODULE.matcher(content); 181 if (m.find()) { 182 return m.replaceAll("").trim(); 183 } 184 return content; 185 } 186 187}