View Javadoc

1   /**
2    * This file Copyright (c) 2003-2012 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.scheduler;
35  
36  import info.magnolia.cms.security.SilentSessionOp;
37  import info.magnolia.commands.CommandsManager;
38  import info.magnolia.commands.chain.Command;
39  import info.magnolia.context.Context;
40  import info.magnolia.context.MgnlContext;
41  import info.magnolia.context.SimpleContext;
42  import info.magnolia.context.SystemContext;
43  import info.magnolia.init.MagnoliaConfigurationProperties;
44  import info.magnolia.objectfactory.Components;
45  import info.magnolia.ui.api.message.Message;
46  import info.magnolia.ui.api.message.MessageType;
47  import info.magnolia.ui.framework.message.MessagesManager;
48  
49  import java.util.Map;
50  
51  import javax.inject.Inject;
52  import javax.jcr.Node;
53  import javax.jcr.RepositoryException;
54  import javax.jcr.Session;
55  
56  import org.apache.commons.lang.StringUtils;
57  import org.quartz.Job;
58  import org.quartz.JobExecutionContext;
59  import org.quartz.JobExecutionException;
60  import org.slf4j.Logger;
61  import org.slf4j.LoggerFactory;
62  
63  /**
64   * A simple job executing a command. The job reads the command and catalog name out of the jobs context. Parameters to
65   * the command are passed by a map under the job data name 'params'.
66   */
67  public class CommandJob implements Job {
68  
69      private static Logger log = LoggerFactory.getLogger(CommandJob.class);
70      private MessagesManager messagesManager;
71  
72      @Inject
73      public CommandJob(MessagesManager messagesManager) {
74          this.messagesManager = messagesManager;
75      }
76  
77      /**
78       * @deprecated since 2.1, please use {@link #CommandJob(MessagesManager)} instead.
79       */
80      @Deprecated
81      public CommandJob() {
82          this.messagesManager = Components.getComponent(MessagesManager.class);
83      }
84  
85      /**
86       * Called by the scheduler. Get the command. Create a magnolia context.
87       */
88      @Override
89      public void execute(JobExecutionContext jobCtx) throws JobExecutionException {
90          log.info("Starting job [{}]...", jobCtx.getJobDetail().getName());
91          Map jobData = jobCtx.getJobDetail().getJobDataMap();
92  
93          String instanceClusterId = Components.getComponent(MagnoliaConfigurationProperties.class).getProperty("magnolia.clusterid");
94          String jobClusterId = null;
95  
96          if (jobData.containsKey(SchedulerConsts.CONFIG_JOB_PARAMS) && jobData.get(SchedulerConsts.CONFIG_JOB_PARAMS) != null) {
97              jobClusterId = (String) ((Map) jobData.get(SchedulerConsts.CONFIG_JOB_PARAMS)).get("clusterId");
98          }
99  
100         String catalogName = (String) jobData.get(SchedulerConsts.CONFIG_JOB_COMMAND_CATALOG);
101         String cmdName = (String) jobData.get(SchedulerConsts.CONFIG_JOB_COMMAND);
102 
103         if (StringUtils.isBlank(jobClusterId) || jobClusterId.equals(instanceClusterId)) {
104             try {
105                 // init context
106                 MgnlContext.setInstance(new SimpleContext(Components.getComponent(SystemContext.class)));
107 
108                 Command cmd = Components.getComponent(CommandsManager.class).getCommand(catalogName, cmdName);
109                 if (cmd == null) {
110                     String errorMessage = "Can't find command [" + cmdName + "] for job in catalog [{" + catalogName + "}]";
111                     logAndSendErrorMessage(errorMessage, new Exception());
112                     return;
113                 }
114 
115                 Context ctx = new SimpleContext();
116                 // copy data, else the jobs context could get manipulated by the commands
117                 if (jobData.containsKey(SchedulerConsts.CONFIG_JOB_PARAMS) && jobData.get(SchedulerConsts.CONFIG_JOB_PARAMS) != null) {
118                     ctx.putAll((Map) jobData.get(SchedulerConsts.CONFIG_JOB_PARAMS));
119 
120                     if (!ctx.containsKey(Context.ATTRIBUTE_UUID) && ctx.containsKey(Context.ATTRIBUTE_PATH) && ctx.containsKey(Context.ATTRIBUTE_REPOSITORY)) {
121                         String uuid = getNodeUUID(ctx);
122                         if (uuid != null) {
123                             ctx.put(Context.ATTRIBUTE_UUID, uuid);
124                         }
125                     }
126                 }
127 
128                 cmd.execute(ctx);
129                 log.info("Job executed successfully [{}]", jobCtx.getJobDetail().getName());
130             } catch (Exception e) {
131                 String errorMessage = "Can't execute command " + catalogName + "-" + cmdName;
132                 logAndSendErrorMessage(errorMessage, e);
133                 throw new JobExecutionException(errorMessage, e, false);
134             } finally {
135                 MgnlContext.setInstance(null);
136             }
137         } else {
138             log.info("Job " + cmdName + " from catalog " + catalogName + " will be executed only in cluster node: " + jobClusterId);
139         }
140     }
141 
142     private void logAndSendErrorMessage(String errorMessage, Exception exception) {
143         log.error(errorMessage, exception);
144         Message message = new Message(MessageType.ERROR, "Scheduler error", errorMessage);
145         messagesManager.sendLocalMessage(message);
146     }
147 
148     private String getNodeUUID(Context ctx) {
149         final String path = ctx.getAttribute(Context.ATTRIBUTE_PATH);
150         final String repository = ctx.getAttribute(Context.ATTRIBUTE_REPOSITORY);
151         if (StringUtils.isBlank(path) || StringUtils.isBlank(repository)) {
152             log.debug("Parameters path and repository cannot be empty.");
153             return null;
154         }
155 
156         return MgnlContext.doInSystemContext(new SilentSessionOp<String>(repository) {
157 
158             @Override
159             public String exec() {
160                 Session session = null;
161                 try {
162                     session = MgnlContext.getJCRSession(repository);
163                 } catch (RepositoryException e) {
164                     log.debug("failed to retrieve repository " + repository + " with " + e.getMessage(), e);
165                     return null;
166                 }
167                 try {
168                     return doExec(session);
169                 } catch (Throwable t) {
170                     log.debug("Failed to execute " + toString() + " session operation with " + t.getMessage(), t);
171                     return null;
172                 }
173             }
174 
175             @Override
176             public String doExec(Session session) throws Throwable {
177                 if (session.itemExists(path)) {
178                     Node node = session.getNode(path);
179                     return node.getIdentifier();
180                 }
181                 log.debug("Node [{}] does not exist in repository [{}]", path, repository);
182                 return null;
183             }
184 
185             @Override
186             public String toString() {
187                 return "get node [ " + repository + ":" + path + "] uuid";
188             }
189         });
190     }
191 }