View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.common.util;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.util.jar.Attributes;
21  import java.util.jar.Manifest;
22  
23  import javax.servlet.ServletContext;
24  
25  import static org.apache.commons.io.IOUtils.*;
26  import static org.apache.commons.lang.StringUtils.*;
27  
28  /**
29   * Obtains version information about the application from the META-INF/MANIFEST.MF file contained inside a .war file
30   */
31  public class ManifestInspector {
32  
33  	/**
34  	 * Location of the MANIFEST.MF file
35  	 */
36  	public static final String MANIFEST_LOCATION = "/META-INF/MANIFEST.MF";
37  	public static final String BUNDLE_NAME = "Bundle-Name";
38  	public static final String BUNDLE_VERSION = "Bundle-Version";
39  	public static final String BUNDLE_TIMESTAMP = "Bundle-Timestamp";
40  	public static final String BUNDLE_BUILD_NUMBER = "Bundle-BuildNumber";
41  	public static final String NO_BUILD_INFORMATION_AVAILABLE = "No build information available";
42  
43  	/**
44  	 * Return a Manifest object
45  	 */
46  	protected Manifest getManifest(ServletContext servletContext) throws IOException {
47  		InputStream in = null;
48  		try {
49  			in = servletContext.getResourceAsStream(MANIFEST_LOCATION);
50  			if (in == null) {
51  				return null;
52  			} else {
53  				return new Manifest(in);
54  			}
55  		} catch (IOException e) {
56  			throw e;
57  		} finally {
58  			closeQuietly(in);
59  		}
60  	}
61  
62  	/**
63  	 * Examine the manifest provided for build information. Returns null if manifest is null
64  	 */
65  	protected BuildInformation getBuildInformation(Manifest manifest) {
66  		// No Manifest is available
67  		if (manifest == null) {
68  			return null;
69  		}
70  
71  		// Extract the attributes
72  		Attributes attributes = manifest.getMainAttributes();
73  
74  		// Manifest attributes containing the build information
75  		String name = attributes.getValue(BUNDLE_NAME);
76  		String version = attributes.getValue(BUNDLE_VERSION);
77  		String buildNumber = attributes.getValue(BUNDLE_BUILD_NUMBER);
78  		String timestamp = attributes.getValue(BUNDLE_TIMESTAMP);
79  
80  		// Create and populate a BuildInformation object
81  		BuildInformation bi = new BuildInformation();
82  		bi.setName(name);
83  		bi.setVersion(version);
84  		bi.setBuildNumber(buildNumber);
85  		bi.setTimestamp(timestamp);
86  		return bi;
87  	}
88  
89  	/**
90  	 * Obtain version information from MANIFEST.MF
91  	 */
92  	public String getBuildInformationString(ServletContext context) throws IOException {
93  		// Get a handle to a Manifest object
94  		Manifest manifest = getManifest(context);
95  
96  		// Store build information attributes from the manifest into a POJO
97  		BuildInformation buildInformation = getBuildInformation(manifest);
98  
99  		// Convert the POJO to a string
100 		return toString(buildInformation);
101 	}
102 
103 	/**
104 	 * Return true if BuildInformation is null or does not contain any meaningful information.
105 	 */
106 	protected boolean isNullOrEmpty(BuildInformation bi) {
107 		if (bi == null) {
108 			return true;
109 		}
110 		if (!isEmpty(bi.getName())) {
111 			return false;
112 		}
113 		if (!isEmpty(bi.getVersion())) {
114 			return false;
115 		}
116 		if (!isEmpty(bi.getBuildNumber())) {
117 			return false;
118 		}
119 		if (!isEmpty(bi.getTimestamp())) {
120 			return false;
121 		}
122 		return true;
123 	}
124 
125 	/**
126 	 * Convert the build information POJO to a display String
127 	 */
128 	public String toString(BuildInformation bi) {
129 		/**
130 		 * For developers pointed at a local build, MANIFEST.MF may not be present
131 		 * 
132 		 * Since we overlay the Rice war file, the MANIFEST.MF from Rice may be present but doesn't contain build
133 		 * information
134 		 */
135 		if (isNullOrEmpty(bi)) {
136 			return NO_BUILD_INFORMATION_AVAILABLE;
137 		}
138 
139 		/**
140 		 * Build number is only present if Hudson has done the build
141 		 */
142 		if (!isEmpty(bi.getBuildNumber())) {
143 			bi.setBuildNumber("#" + bi.getBuildNumber());
144 		}
145 
146 		/**
147 		 * Build a string out of the build information
148 		 */
149 		StringBuffer sb = new StringBuffer();
150 		if (!isEmpty(bi.getName())) {
151 			sb.append(bi.getName());
152 			sb.append(" :: ");
153 		}
154 		if (!isEmpty(bi.getVersion())) {
155 			sb.append(bi.getVersion());
156 			sb.append(" :: ");
157 		}
158 		if (!isEmpty(bi.getBuildNumber())) {
159 			sb.append(bi.getBuildNumber());
160 			sb.append(" :: ");
161 		}
162 		if (!isEmpty(bi.getTimestamp())) {
163 			sb.append(bi.getTimestamp());
164 		}
165 		return sb.toString();
166 	}
167 }