1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.admin.action;
24  
25  import com.liferay.portal.kernel.cache.CacheRegistry;
26  import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
27  import com.liferay.portal.kernel.security.permission.PermissionChecker;
28  import com.liferay.portal.kernel.util.Constants;
29  import com.liferay.portal.kernel.util.ParamUtil;
30  import com.liferay.portal.kernel.util.PortalClassInvoker;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.kernel.webcache.WebCachePoolUtil;
34  import com.liferay.portal.lastmodified.LastModifiedCSS;
35  import com.liferay.portal.lastmodified.LastModifiedJavaScript;
36  import com.liferay.portal.lucene.LuceneIndexer;
37  import com.liferay.portal.security.auth.PrincipalException;
38  import com.liferay.portal.struts.PortletAction;
39  import com.liferay.portal.struts.StrutsUtil;
40  import com.liferay.portal.theme.ThemeDisplay;
41  import com.liferay.portal.util.PortalInstances;
42  import com.liferay.portal.util.PortalUtil;
43  import com.liferay.portal.util.PrefsPropsUtil;
44  import com.liferay.portal.util.PropsUtil;
45  import com.liferay.portal.util.ShutdownUtil;
46  import com.liferay.portal.util.WebKeys;
47  import com.liferay.util.Time;
48  import com.liferay.util.servlet.NullServletResponse;
49  import com.liferay.util.servlet.SessionErrors;
50  
51  import java.lang.reflect.Method;
52  
53  import java.util.Enumeration;
54  import java.util.Iterator;
55  import java.util.Map;
56  import java.util.Set;
57  import java.util.TreeSet;
58  
59  import javax.portlet.ActionRequest;
60  import javax.portlet.ActionResponse;
61  import javax.portlet.PortletConfig;
62  import javax.portlet.PortletPreferences;
63  
64  import javax.servlet.RequestDispatcher;
65  import javax.servlet.ServletContext;
66  import javax.servlet.http.HttpServletRequest;
67  import javax.servlet.http.HttpServletResponse;
68  
69  import org.apache.commons.logging.Log;
70  import org.apache.commons.logging.LogFactory;
71  import org.apache.log4j.Level;
72  import org.apache.log4j.Logger;
73  import org.apache.struts.action.ActionForm;
74  import org.apache.struts.action.ActionMapping;
75  
76  import org.dom4j.Document;
77  import org.dom4j.Element;
78  
79  /**
80   * <a href="EditServerAction.java.html"><b><i>View Source</i></b></a>
81   *
82   * @author Brian Wing Shun Chan
83   *
84   */
85  public class EditServerAction extends PortletAction {
86  
87      public void processAction(
88              ActionMapping mapping, ActionForm form, PortletConfig config,
89              ActionRequest req, ActionResponse res)
90          throws Exception {
91  
92          ThemeDisplay themeDisplay =
93              (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
94  
95          PermissionChecker permissionChecker =
96              themeDisplay.getPermissionChecker();
97  
98          if (!permissionChecker.isOmniadmin()) {
99              SessionErrors.add(req, PrincipalException.class.getName());
100 
101             setForward(req, "portlet.admin.error");
102 
103             return;
104         }
105 
106         PortletPreferences prefs = PrefsPropsUtil.getPreferences();
107 
108         String cmd = ParamUtil.getString(req, Constants.CMD);
109 
110         if (cmd.equals("addLogLevel")) {
111             addLogLevel(req);
112         }
113         else if (cmd.equals("cacheDb")) {
114             cacheDb();
115         }
116         else if (cmd.equals("cacheMulti")) {
117             cacheMulti();
118         }
119         else if (cmd.equals("cacheSingle")) {
120             cacheSingle();
121         }
122         else if (cmd.equals("gc")) {
123             gc();
124         }
125         else if (cmd.equals("precompile")) {
126             precompile(req, res);
127         }
128         else if (cmd.equals("reIndex")) {
129             reIndex();
130         }
131         else if (cmd.equals("shutdown")) {
132             shutdown(req);
133         }
134         else if (cmd.equals("threadDump")) {
135             threadDump();
136         }
137         else if (cmd.equals("updateLogLevels")) {
138             updateLogLevels(req);
139         }
140         else if (cmd.equals("updateOpenOffice")) {
141             updateOpenOffice(req, prefs);
142         }
143 
144         sendRedirect(req, res);
145     }
146 
147     protected void addLogLevel(ActionRequest req) throws Exception {
148         String loggerName = ParamUtil.getString(req, "loggerName");
149         String priority = ParamUtil.getString(req, "priority");
150 
151         Logger logger = Logger.getLogger(loggerName);
152 
153         logger.setLevel(Level.toLevel(priority));
154     }
155 
156     protected void cacheDb() throws Exception {
157         CacheRegistry.clear();
158     }
159 
160     protected void cacheMulti() throws Exception {
161         MultiVMPoolUtil.clear();
162     }
163 
164     protected void cacheSingle() throws Exception {
165         LastModifiedCSS.clear();
166         LastModifiedJavaScript.clear();
167         WebCachePoolUtil.clear();
168     }
169 
170     protected void gc() throws Exception {
171         Runtime.getRuntime().gc();
172     }
173 
174     protected void jvm4ThreadDump(StringBuffer sb, ThreadGroup group) {
175         Thread[] threads = new Thread[group.activeCount()];
176 
177         group.enumerate(threads, false);
178 
179         for (int i = 0; i < threads.length && threads[i] != null; i++) {
180             Thread thread = threads[i];
181 
182             sb.append(StringPool.QUOTE);
183             sb.append(thread.getName());
184             sb.append(StringPool.QUOTE);
185 
186             if (thread.getThreadGroup() != null) {
187                 sb.append(StringPool.SPACE);
188                 sb.append(StringPool.OPEN_PARENTHESIS);
189                 sb.append(thread.getThreadGroup().getName());
190                 sb.append(StringPool.CLOSE_PARENTHESIS);
191             }
192 
193             sb.append(", priority=" + thread.getPriority());
194             sb.append("\n");
195         }
196 
197         ThreadGroup[] groups = new ThreadGroup[group.activeGroupCount()];
198 
199         group.enumerate(groups, false);
200 
201         for (int i = 0; i < groups.length && groups[i] != null; i++) {
202             jvm4ThreadDump(sb, groups[i]);
203         }
204     }
205 
206     protected void precompile(ActionRequest req, ActionResponse res)
207         throws Exception {
208 
209         Set jsps = new TreeSet();
210 
211         ServletContext ctx = (ServletContext)req.getAttribute(WebKeys.CTX);
212 
213         // Struts
214 
215         Document doc = PortalUtil.readDocumentFromStream(
216             ctx.getResourceAsStream("/WEB-INF/struts-config.xml"));
217 
218         Element root = doc.getRootElement();
219 
220         Iterator itr1 = root.element("global-forwards").elements(
221             "forward").iterator();
222 
223         while (itr1.hasNext()) {
224             Element action = (Element)itr1.next();
225 
226             String fileName = action.attributeValue("path");
227 
228             if ((Validator.isNotNull(fileName)) &&
229                 (fileName.endsWith(".jsp"))) {
230 
231                 jsps.add(fileName);
232             }
233         }
234 
235         itr1 = root.element("action-mappings").elements("action").iterator();
236 
237         while (itr1.hasNext()) {
238             Element action = (Element)itr1.next();
239 
240             String fileName = action.attributeValue("forward");
241 
242             if ((Validator.isNotNull(fileName)) &&
243                 (fileName.endsWith(".jsp"))) {
244 
245                 jsps.add(fileName);
246             }
247             else {
248                 Iterator itr2 = action.elements("forward").iterator();
249 
250                 while (itr2.hasNext()) {
251                     Element forward = (Element)itr2.next();
252 
253                     fileName = forward.attributeValue("path");
254 
255                     if ((Validator.isNotNull(fileName)) &&
256                         (fileName.endsWith(".jsp"))) {
257 
258                         jsps.add(fileName);
259                     }
260                 }
261             }
262         }
263 
264         // Tiles
265 
266         doc = PortalUtil.readDocumentFromStream(
267             ctx.getResourceAsStream("/WEB-INF/tiles-defs.xml"));
268 
269         root = doc.getRootElement();
270 
271         itr1 = root.elements("definition").iterator();
272 
273         while (itr1.hasNext()) {
274             Element definition = (Element)itr1.next();
275 
276             String fileName = definition.attributeValue("path");
277 
278             if ((Validator.isNotNull(fileName)) &&
279                 (fileName.endsWith(".jsp"))) {
280 
281                 jsps.add(fileName);
282             }
283             else {
284                 Iterator itr2 = definition.elements("put").iterator();
285 
286                 while (itr2.hasNext()) {
287                     Element put = (Element)itr2.next();
288 
289                     fileName = put.attributeValue("value");
290 
291                     if ((Validator.isNotNull(fileName)) &&
292                         (fileName.endsWith(".jsp"))) {
293 
294                         jsps.add(fileName);
295                     }
296                 }
297             }
298         }
299 
300         // Precompile JSPs
301 
302         HttpServletRequest httpReq = PortalUtil.getHttpServletRequest(req);
303         HttpServletResponse httpRes = new NullServletResponse(
304             PortalUtil.getHttpServletResponse(res));
305 
306         itr1 = jsps.iterator();
307 
308         while (itr1.hasNext()) {
309             try {
310                 String jsp = StrutsUtil.TEXT_HTML_DIR + itr1.next();
311 
312                 RequestDispatcher rd = ctx.getRequestDispatcher(jsp);
313 
314                 if (rd != null) {
315                     if (_log.isInfoEnabled()) {
316                         _log.info("Precompiling " + jsp);
317                     }
318 
319                     rd.include(httpReq, httpRes);
320                 }
321             }
322             catch (Exception e) {
323                 _log.debug(e, e);
324             }
325         }
326     }
327 
328     protected void reIndex() throws Exception {
329         long[] companyIds = PortalInstances.getCompanyIds();
330 
331         for (int i = 0; i < companyIds.length; i++) {
332             long companyId = companyIds[i];
333 
334             try {
335                 LuceneIndexer indexer = new LuceneIndexer(companyId);
336 
337                 indexer.reIndex();
338             }
339             catch (Exception e) {
340                 _log.error(e, e);
341             }
342         }
343     }
344 
345     protected void shutdown(ActionRequest req) throws Exception {
346         long minutes = ParamUtil.getInteger(req, "minutes") * Time.MINUTE;
347         String message = ParamUtil.getString(req, "message");
348 
349         if (minutes <= 0) {
350             ShutdownUtil.cancel();
351         }
352         else {
353             ShutdownUtil.shutdown(minutes, message);
354         }
355     }
356 
357     protected void threadDump() throws Exception {
358         String jvm =
359             System.getProperty("java.vm.name") + " " +
360                 System.getProperty("java.vm.version");
361 
362         StringBuffer sb = null;
363 
364         try {
365             sb = new StringBuffer("Full thread dump " + jvm + "\n\n");
366 
367             Map stackTraces = (Map)PortalClassInvoker.invoke(
368                 Thread.class.getName(), "getAllStackTraces", false);
369 
370             Class[] nullParams = new Class[] {};
371             Object[] nullArgs = new Object[] {};
372 
373             Method getId = Thread.class.getMethod("getId", nullParams);
374             Method getState = Thread.class.getMethod("getState", nullParams);
375 
376             Iterator itr = stackTraces.keySet().iterator();
377 
378             while (itr.hasNext()) {
379                 Thread thread = (Thread)itr.next();
380 
381                 StackTraceElement[] elements =
382                     (StackTraceElement[])stackTraces.get(thread);
383 
384                 sb.append(StringPool.QUOTE);
385                 sb.append(thread.getName());
386                 sb.append(StringPool.QUOTE);
387 
388                 if (thread.getThreadGroup() != null) {
389                     sb.append(StringPool.SPACE);
390                     sb.append(StringPool.OPEN_PARENTHESIS);
391                     sb.append(thread.getThreadGroup().getName());
392                     sb.append(StringPool.CLOSE_PARENTHESIS);
393                 }
394 
395                 sb.append(", priority=" + thread.getPriority());
396                 sb.append(", id=" + getId.invoke(thread, nullArgs));
397                 sb.append(", state=" + getState.invoke(thread, nullArgs));
398                 sb.append("\n");
399 
400                 for (int i = 0; i < elements.length; i++) {
401                     sb.append("\t" + elements[i] + "\n");
402                 }
403 
404                 sb.append("\n");
405             }
406         }
407         catch (Exception e) {
408             ThreadGroup root = Thread.currentThread().getThreadGroup();
409 
410             while (root.getParent() != null) {
411                 root = root.getParent();
412             }
413 
414             sb = new StringBuffer("Summarized thread dump " + jvm + "\n\n");
415 
416             jvm4ThreadDump(sb, root);
417         }
418 
419         _log.info(sb.toString());
420     }
421 
422     protected void updateLogLevels(ActionRequest req) throws Exception {
423         Enumeration enu = req.getParameterNames();
424 
425         while (enu.hasMoreElements()) {
426             String name = (String)enu.nextElement();
427 
428             if (name.startsWith("logLevel")) {
429                 String loggerName = name.substring(8, name.length());
430 
431                 String priority = ParamUtil.getString(
432                     req, name, Level.INFO.toString());
433 
434                 Logger logger = Logger.getLogger(loggerName);
435 
436                 logger.setLevel(Level.toLevel(priority));
437             }
438         }
439     }
440 
441     protected void updateOpenOffice(ActionRequest req, PortletPreferences prefs)
442         throws Exception {
443 
444         boolean enabled = ParamUtil.getBoolean(req, "enabled");
445         String host = ParamUtil.getString(req, "host");
446         int port = ParamUtil.getInteger(req, "port");
447 
448         prefs.setValue(
449             PropsUtil.OPENOFFICE_SERVER_ENABLED, String.valueOf(enabled));
450         prefs.setValue(PropsUtil.OPENOFFICE_SERVER_HOST, host);
451         prefs.setValue(PropsUtil.OPENOFFICE_SERVER_PORT, String.valueOf(port));
452 
453         prefs.store();
454     }
455 
456     private static Log _log = LogFactory.getLog(EditServerAction.class);
457 
458 }