001package com.randomnoun.common.servlet; 002 003/* (c) 2013-2016 randomnoun. All Rights Reserved. This work is licensed under a 004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html) 005 */ 006 007import java.io.File; 008import java.io.FileInputStream; 009import java.io.IOException; 010import java.io.InputStream; 011import java.util.Properties; 012 013import jakarta.servlet.ServletException; 014import jakarta.servlet.http.HttpServlet; 015import jakarta.servlet.http.HttpServletRequest; 016import jakarta.servlet.http.HttpServletResponse; 017 018import org.apache.log4j.Logger; 019import org.json.JSONObject; 020 021/** 022 * Reads the contents of the build.properties file in the 023 * current application and sends it to the browser in a 024 * variety of forms. Probably JSON for starters. 025 * 026 * <p>The properties file must be located on the classpath at the 027 * location "/build.properties". 028 * 029 * <p>For this to work, the application needs to have been built 030 * through maven (and possibly bamboo), and there should be a 031 * <code>build.properties</code> file in the application being created, 032 * with the contents: 033 * 034 * <pre> 035 * bamboo.buildKey=${bambooBuildKey} 036 bamboo.buildNumber=${bambooBuildNumber} 037 bamboo.buildPlanName=${bambooBuildPlanName} 038 bamboo.buildTimeStamp=${bambooBuildTimeStamp} 039 bamboo.buildForceCleanCheckout=${bambooForceCleanCheckout} 040 bamboo.custom.cvs.last.update.time=${bambooCustomCvsLastUpdateTime} 041 bamboo.custom.cvs.last.update.time.label=${bambooCustomCvsLastUpdateTimeLabel} 042 043 maven.pom.name=${pom.name} 044 maven.pom.version=${pom.version} 045 maven.pom.groupId=${pom.groupId} 046 maven.pom.artifactId=${pom.artifactId} 047 </pre> 048 * 049 * and the bamboo plan should have the following in the bamboo plan's 050 * stage's job's task's maven goal specification: 051 * 052 * <pre> 053 * "-DbambooBuildKey=${bamboo.buildKey}" 054 "-DbambooBuildNumber=${bamboo.buildNumber}" 055 "-DbambooBuildPlanName=${bamboo.buildPlanName}" 056 "-DbambooBuildTimeStamp=${bamboo.buildTimeStamp}" 057 "-DbambooBuildForceCleanCheckout=${bamboo.buildForceCleanCheckout}" 058 "-DbambooCustomCvsLastUpdateTime=${bamboo.custom.cvs.last.update.time}" 059 "-DbambooCustomCvsLastUpdateTimeLabel=${bamboo.custom.cvs.last.update.time.label}" 060 -DuniqueVersion=false 061 * </pre> 062 * 063 * <p>This script will also look for a build.properties file in /etc/build.properties; 064 * this should exist on docker containers built by bamboo. If this exists, it is also 065 * included in the JSON output under the "/etc/build.properties" key. 066 * 067 * 068 * @author knoxg 069 * @see <a href="http://www.randomnoun.com/wp/2013/09/24/webapp-versions-v1-0/">http://www.randomnoun.com/wp/2013/09/24/webapp-versions-v1-0/</a> 070 * 071 */ 072public class VersionServlet extends HttpServlet { 073 074 /** Generated serialVersionUID */ 075 private static final long serialVersionUID = -6978469440912690523L; 076 077 /** Logger for this class */ 078 public static final Logger logger = Logger.getLogger(VersionServlet.class); 079 080 081 /** Post method; just defers to get 082 * 083 * @see jakarta.servlet.http.HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 084 */ 085 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 086 doGet(request, response); 087 } 088 089 /** If a property has not been populated through the maven resource filter 090 * mechanism, then remove it from the Properties object. 091 * 092 * @param props Properties object 093 * @param key key to check 094 * @param value default value 095 */ 096 private void removeDefaultProperty(Properties props, String key, String value) { 097 if (("${" + value + "}").equals(props.get(key))) { 098 props.remove(key); 099 } 100 } 101 102 /** Removes build properties that were not set during the build process 103 * (i.e. are still set to '${xxx}' placeholders). 104 * 105 * @param props Properties object 106 */ 107 private void removeDefaultProperties(Properties props) { 108 // projects not built in bamboo won't set these 109 removeDefaultProperty(props, "bamboo.buildKey", "bambooBuildKey"); 110 removeDefaultProperty(props, "bamboo.buildNumber", "bambooBuildNumber"); 111 removeDefaultProperty(props, "bamboo.buildPlanName", "bambooBuildPlanName"); 112 removeDefaultProperty(props, "bamboo.buildTimeStamp", "bambooBuildTimeStamp"); 113 removeDefaultProperty(props, "bamboo.buildForceCleanCheckout", "bambooForceCleanCheckout"); 114 // bamboo.custom.cvs.last.update.time == "${bambooCustomCvsLastUpdateTime}" 115 // if there is no -Dbamboo.custom.cvs.last.update.time property on mvn build cmdline 116 removeDefaultProperty(props, "bamboo.custom.cvs.last.update.time", "bambooCustomCvsLastUpdateTime"); 117 removeDefaultProperty(props, "bamboo.custom.cvs.last.update.time.label", "bambooCustomCvsLastUpdateTimeLabel"); 118 // bamboo.custom.cvs.last.update.time == "${bamboo.custom.cvs.last.update.time}" 119 // if there IS a -Dbamboo.custom.cvs.last.update.time property on mvn build cmdline 120 // but it's not set by bamboo (because it's now a git project, but the mvn cmdline hasn't been changed) 121 removeDefaultProperty(props, "bamboo.custom.cvs.last.update.time", "bamboo.custom.cvs.last.update.time"); 122 removeDefaultProperty(props, "bamboo.custom.cvs.last.update.time.label", "bamboo.custom.cvs.last.update.time.label"); 123 124 125 // bamboo git projects have some extra properties we could include here; 126 // bamboo.repository.git.branch 127 // bamboo.repository.git.repositoryUrl 128 // see https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html 129 130 // projects in cvs repositories won't set this 131 removeDefaultProperty(props, "git.buildNumber", "buildNumber"); 132 } 133 134 /** See class documentation 135 * 136 * @see jakarta.servlet.http.HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 137 */ 138 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 139 { 140 InputStream is = VersionServlet.class.getClassLoader().getResourceAsStream("/build.properties"); 141 Properties props = new Properties(); 142 if (is==null) { 143 props.put("error", "Missing build.properties"); 144 } else { 145 props.load(is); 146 is.close(); 147 } 148 149 removeDefaultProperties(props); 150 File etcPropsFile = new File("/etc/build.properties"); 151 if (etcPropsFile.exists()) { 152 Properties etcProps = new Properties(); 153 is = new FileInputStream(etcPropsFile); 154 etcProps.load(is); 155 is.close(); 156 removeDefaultProperties(etcProps); 157 props.put("/etc/build.properties", etcProps); 158 } 159 160 response.setHeader("Content-Type", "application/json"); 161 response.setStatus(HttpServletResponse.SC_OK); 162 response.getWriter().println(new JSONObject(props).toString()); 163 } 164}