001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.console.configmanager;
017:
018: import java.io.ByteArrayInputStream;
019: import java.io.File;
020: import java.io.FileInputStream;
021: import java.io.IOException;
022: import java.io.StringWriter;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.ArrayList;
026: import javax.enterprise.deploy.shared.factories.DeploymentFactoryManager;
027: import javax.enterprise.deploy.spi.DeploymentManager;
028: import javax.enterprise.deploy.spi.Target;
029: import javax.enterprise.deploy.spi.TargetModuleID;
030: import javax.enterprise.deploy.spi.status.ProgressObject;
031: import javax.portlet.ActionRequest;
032: import javax.portlet.ActionResponse;
033: import javax.portlet.PortletConfig;
034: import javax.portlet.PortletException;
035: import javax.portlet.PortletRequestDispatcher;
036: import javax.portlet.RenderRequest;
037: import javax.portlet.RenderResponse;
038: import javax.xml.parsers.DocumentBuilder;
039:
040: import org.apache.commons.fileupload.FileItem;
041: import org.apache.commons.fileupload.FileUploadException;
042: import org.apache.commons.fileupload.disk.DiskFileItemFactory;
043: import org.apache.commons.fileupload.portlet.PortletFileUpload;
044: import org.apache.commons.logging.Log;
045: import org.apache.commons.logging.LogFactory;
046: import org.apache.geronimo.console.BasePortlet;
047: import org.apache.geronimo.deployment.plugin.jmx.JMXDeploymentManager;
048: import org.apache.geronimo.deployment.plugin.ConfigIDExtractor;
049: import org.apache.geronimo.common.DeploymentException;
050: import org.apache.geronimo.kernel.repository.Artifact;
051: import org.apache.geronimo.kernel.util.XmlUtil;
052: import org.apache.geronimo.upgrade.Upgrade1_0To1_1;
053: import org.w3c.dom.Document;
054:
055: /**
056: * $Rev: 613391 $ $Date: 2008-01-19 05:47:33 -0800 (Sat, 19 Jan 2008) $
057: */
058: public class DeploymentPortlet extends BasePortlet {
059: private final static Log log = LogFactory
060: .getLog(DeploymentPortlet.class);
061:
062: private static final String DEPLOY_VIEW = "/WEB-INF/view/configmanager/deploy.jsp";
063: private static final String HELP_VIEW = "/WEB-INF/view/configmanager/deployHelp.jsp";
064: private static final String MIGRATED_PLAN_PARM = "migratedPlan";
065: private static final String ORIGINAL_PLAN_PARM = "originalPlan";
066: private static final String FULL_STATUS_PARM = "fullStatusMessage";
067: private static final String ABBR_STATUS_PARM = "abbrStatusMessage";
068: private PortletRequestDispatcher deployView;
069: private PortletRequestDispatcher helpView;
070:
071: public void processAction(ActionRequest actionRequest,
072: ActionResponse actionResponse) throws PortletException,
073: IOException {
074: if (!PortletFileUpload.isMultipartContent(actionRequest)) {
075: throw new PortletException("Expected file upload");
076: }
077:
078: File rootDir = new File(System.getProperty("java.io.tmpdir"));
079: PortletFileUpload uploader = new PortletFileUpload(
080: new DiskFileItemFactory(10240, rootDir));
081: File moduleFile = null;
082: File planFile = null;
083: String startApp = null;
084: String redeploy = null;
085: try {
086: List items = uploader.parseRequest(actionRequest);
087: for (Iterator i = items.iterator(); i.hasNext();) {
088: FileItem item = (FileItem) i.next();
089: if (!item.isFormField()) {
090: String fieldName = item.getFieldName();
091: String name = item.getName().trim();
092: File file;
093: if (name.length() == 0) {
094: file = null;
095: } else {
096: // Firefox sends basename, IE sends full path
097: int index = name.lastIndexOf('\\');
098: if (index != -1) {
099: name = name.substring(index + 1);
100: }
101: file = new File(rootDir, name);
102: }
103: if ("module".equals(fieldName)) {
104: moduleFile = file;
105: } else if ("plan".equals(fieldName)) {
106: planFile = file;
107: }
108: if (file != null) {
109: try {
110: item.write(file);
111: } catch (Exception e) {
112: throw new PortletException(e);
113: }
114: }
115: } else {
116: // retrieve 'startApp' form field value
117: if ("startApp"
118: .equalsIgnoreCase(item.getFieldName())) {
119: startApp = item.getString();
120: } else if ("redeploy".equalsIgnoreCase(item
121: .getFieldName())) {
122: redeploy = item.getString();
123: }
124: }
125: }
126: } catch (FileUploadException e) {
127: throw new PortletException(e);
128: }
129: DeploymentFactoryManager dfm = DeploymentFactoryManager
130: .getInstance();
131: FileInputStream fis = null;
132: try {
133: DeploymentManager mgr = dfm.getDeploymentManager(
134: "deployer:geronimo:inVM", null, null);
135: try {
136: boolean isRedeploy = redeploy != null
137: && !redeploy.equals("");
138: if (mgr instanceof JMXDeploymentManager) {
139: ((JMXDeploymentManager) mgr).setLogConfiguration(
140: false, true);
141: }
142: Target[] all = mgr.getTargets();
143: if (null == all) {
144: throw new IllegalStateException(
145: "No target to distribute to");
146: }
147:
148: ProgressObject progress;
149: if (isRedeploy) {
150: TargetModuleID[] targets = identifyTargets(
151: moduleFile, planFile, mgr
152: .getAvailableModules(null, all));
153: if (targets.length == 0) {
154: throw new PortletException(
155: "Unable to identify modules to replace. Please include a Geronimo deployment plan or use the command-line deployment tool.");
156: }
157: progress = mgr.redeploy(targets, moduleFile,
158: planFile);
159: } else {
160: progress = mgr.distribute(new Target[] { all[0] },
161: moduleFile, planFile);
162: }
163: while (progress.getDeploymentStatus().isRunning()) {
164: Thread.sleep(100);
165: }
166:
167: String abbrStatusMessage;
168: String fullStatusMessage = null;
169: if (progress.getDeploymentStatus().isCompleted()) {
170: abbrStatusMessage = "The application was successfully "
171: + (isRedeploy ? "re" : "")
172: + "deployed.<br/>";
173: // start installed app/s
174: if (!isRedeploy && startApp != null
175: && !startApp.equals("")) {
176: progress = mgr.start(progress
177: .getResultTargetModuleIDs());
178: while (progress.getDeploymentStatus()
179: .isRunning()) {
180: Thread.sleep(100);
181: }
182: abbrStatusMessage += "The application was successfully started";
183: }
184: } else {
185: fullStatusMessage = progress.getDeploymentStatus()
186: .getMessage();
187: // for the abbreviated status message clip off everything
188: // after the first line, which in most cases means the gnarly stacktrace
189: abbrStatusMessage = "Deployment failed:<br/>"
190: + fullStatusMessage.substring(0,
191: fullStatusMessage.indexOf('\n'));
192: // try to provide an upgraded version of the plan
193: try {
194: if (planFile != null && planFile.exists()) {
195: byte[] plan = new byte[(int) planFile
196: .length()];
197: fis = new FileInputStream(planFile);
198: fis.read(plan);
199: DocumentBuilder documentBuilder = XmlUtil
200: .newDocumentBuilderFactory()
201: .newDocumentBuilder();
202: Document doc = documentBuilder
203: .parse(new ByteArrayInputStream(
204: plan));
205: // v1.1 switched from configId to moduleId
206: String configId = doc.getDocumentElement()
207: .getAttribute("configId");
208: if (configId != null
209: && !("".equals(configId))) {
210: StringWriter sw = new StringWriter();
211: new Upgrade1_0To1_1().upgrade(
212: new ByteArrayInputStream(plan),
213: sw);
214: // have to store the original and upgraded plans in the session
215: // because the buffer size for render parameters is sometimes not
216: // big enough
217: actionRequest.getPortletSession()
218: .setAttribute(
219: MIGRATED_PLAN_PARM,
220: sw.getBuffer());
221: actionRequest.getPortletSession()
222: .setAttribute(
223: ORIGINAL_PLAN_PARM,
224: new String(plan));
225: }
226: }
227: } catch (Exception e) {
228: // cannot provide a migrated plan in this case, most likely
229: // because the deployment plan would not parse. a valid
230: // status message has already been provided in this case
231: }
232: }
233: // have to store the status messages in the portlet session
234: // because the buffer size for render parameters is sometimes not big enough
235: actionRequest.getPortletSession().setAttribute(
236: FULL_STATUS_PARM, fullStatusMessage);
237: actionRequest.getPortletSession().setAttribute(
238: ABBR_STATUS_PARM, abbrStatusMessage);
239: } finally {
240: mgr.release();
241: if (fis != null)
242: fis.close();
243: if (moduleFile != null && moduleFile.exists()) {
244: if (!moduleFile.delete()) {
245: log.debug("Unable to delete temporary file "
246: + moduleFile);
247: moduleFile.deleteOnExit();
248: }
249: }
250: if (planFile != null && planFile.exists()) {
251: if (!planFile.delete()) {
252: log.debug("Unable to delete temporary file "
253: + planFile);
254: planFile.deleteOnExit();
255: }
256: }
257: }
258: } catch (Exception e) {
259: throw new PortletException(e);
260: }
261: }
262:
263: private TargetModuleID[] identifyTargets(File module, File plan,
264: TargetModuleID[] allModules) throws PortletException {
265: String moduleId = null;
266: List modules = new ArrayList();
267: try {
268: if (plan != null) {
269: moduleId = ConfigIDExtractor
270: .extractModuleIdFromPlan(plan);
271: } else if (module != null) {
272: moduleId = ConfigIDExtractor
273: .extractModuleIdFromArchive(module);
274: if (moduleId == null) {
275: int pos = module.getName().lastIndexOf('.');
276: moduleId = pos > -1 ? module.getName().substring(0,
277: pos) : module.getName();
278: }
279: }
280: if (moduleId != null) {
281: modules.addAll(ConfigIDExtractor
282: .identifyTargetModuleIDs(allModules, moduleId,
283: true));
284: } else {
285: String name = module != null ? module.getName() : plan
286: .getName();
287: int pos = name.lastIndexOf('.');
288: if (pos > -1) {
289: name = name.substring(0, pos);
290: }
291: modules.addAll(ConfigIDExtractor
292: .identifyTargetModuleIDs(allModules,
293: Artifact.DEFAULT_GROUP_ID + "/" + name
294: + "//", true));
295: }
296: } catch (IOException e) {
297: throw new PortletException("Unable to read input files: "
298: + e.getMessage());
299: } catch (DeploymentException e) {
300: throw new PortletException(e.getMessage(), e);
301: }
302: return (TargetModuleID[]) modules
303: .toArray(new TargetModuleID[modules.size()]);
304: }
305:
306: protected void doView(RenderRequest renderRequest,
307: RenderResponse renderResponse) throws PortletException,
308: IOException {
309: // The deployment plans and messages from the deployers sometime exceeds
310: // the buffer size for render attributes. To avoid the buffer
311: // overrun the render attributes are temporarily stored in the portlet
312: // session during the processAction phase and then copied into render
313: // attributes here so the JSP has easier access to them. This seems
314: // to only be an issue on tomcat.
315: copyRenderAttribute(renderRequest, FULL_STATUS_PARM);
316: copyRenderAttribute(renderRequest, ABBR_STATUS_PARM);
317: copyRenderAttribute(renderRequest, MIGRATED_PLAN_PARM);
318: copyRenderAttribute(renderRequest, ORIGINAL_PLAN_PARM);
319: deployView.include(renderRequest, renderResponse);
320: }
321:
322: private void copyRenderAttribute(RenderRequest renderRequest,
323: String attr) {
324: Object value = renderRequest.getPortletSession().getAttribute(
325: attr);
326: renderRequest.getPortletSession().removeAttribute(attr);
327: renderRequest.setAttribute(attr, value);
328: }
329:
330: protected void doHelp(RenderRequest renderRequest,
331: RenderResponse renderResponse) throws PortletException,
332: IOException {
333: helpView.include(renderRequest, renderResponse);
334: }
335:
336: public void init(PortletConfig portletConfig)
337: throws PortletException {
338: super .init(portletConfig);
339: deployView = portletConfig.getPortletContext()
340: .getRequestDispatcher(DEPLOY_VIEW);
341: helpView = portletConfig.getPortletContext()
342: .getRequestDispatcher(HELP_VIEW);
343: }
344:
345: public void destroy() {
346: deployView = null;
347: helpView = null;
348: super.destroy();
349: }
350: }
|