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