001/*
002 * (C) Copyright 2007-2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.scheduler;
020
021import java.io.Serializable;
022import java.util.HashMap;
023import java.util.Map;
024
025import javax.security.auth.login.LoginContext;
026import javax.security.auth.login.LoginException;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.ecm.core.api.impl.UserPrincipal;
031import org.nuxeo.ecm.core.event.Event;
032import org.nuxeo.ecm.core.event.EventContext;
033import org.nuxeo.ecm.core.event.EventService;
034import org.nuxeo.ecm.core.event.impl.EventContextImpl;
035import org.nuxeo.ecm.core.event.impl.EventImpl;
036import org.nuxeo.runtime.api.Framework;
037import org.nuxeo.runtime.api.login.LoginAs;
038import org.nuxeo.runtime.transaction.TransactionHelper;
039import org.quartz.Job;
040import org.quartz.JobDataMap;
041import org.quartz.JobExecutionContext;
042import org.quartz.JobExecutionException;
043
044/**
045 * A Quartz job whose execution sends a configured event.
046 */
047public class EventJob implements Job {
048
049    private static final Log log = LogFactory.getLog(EventJob.class);
050
051    /**
052     * Job execution to send the configured event.
053     */
054    @Override
055    public void execute(JobExecutionContext context) throws JobExecutionException {
056        JobDataMap dataMap = context.getJobDetail().getJobDataMap();
057
058        // switch to the Nuxeo classloader so that the event listeners
059        // work as usual
060
061        ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
062        ClassLoader nuxeoCL = getClass().getClassLoader();
063        Thread.currentThread().setContextClassLoader(nuxeoCL);
064        try {
065            execute(dataMap);
066        } catch (LoginException e) {
067            String eventId = dataMap.getString("eventId");
068            log.error("Error while processing scheduled event id: " + eventId, e);
069        } finally {
070            Thread.currentThread().setContextClassLoader(oldCL);
071        }
072    }
073
074    protected void execute(JobDataMap dataMap) throws LoginException {
075        String eventId = dataMap.getString("eventId");
076        String eventCategory = dataMap.getString("eventCategory");
077        String username = dataMap.getString("username");
078
079        SchedulerService scheduler = Framework.getLocalService(SchedulerService.class);
080        if (scheduler == null || !scheduler.hasApplicationStarted()) {
081            // too early
082            return;
083        }
084
085        EventService eventService = Framework.getService(EventService.class);
086        if (eventService == null) {
087            log.error("Cannot find EventService");
088            return;
089        }
090
091        LoginContext loginContext = null;
092        try {
093            // login
094            if (username == null) {
095                loginContext = Framework.login();
096            } else {
097                if (Framework.getLocalService(LoginAs.class) != null) {
098                    loginContext = Framework.loginAsUser(username);
099                } else if (!Framework.isTestModeSet()) {
100                    log.error("LoginAs service not available");
101                }
102            }
103
104            // set up event context
105            UserPrincipal principal = new UserPrincipal(username, null, false, false);
106            EventContext eventContext = new EventContextImpl(null, principal);
107            eventContext.setProperty("category", eventCategory);
108            eventContext.setProperties(getWrappedMap(dataMap));
109            Event event = new EventImpl(eventId, eventContext);
110
111            // start transaction
112            boolean tx = TransactionHelper.startTransaction();
113
114            // send event
115            log.debug("Sending scheduled event id=" + eventId + ", category=" + eventCategory + ", username="
116                    + username);
117            boolean ok = false;
118            try {
119                eventService.fireEvent(event);
120                ok = true;
121            } finally {
122                if (tx) {
123                    if (!ok) {
124                        TransactionHelper.setTransactionRollbackOnly();
125                    }
126                    TransactionHelper.commitOrRollbackTransaction();
127                }
128            }
129        } finally {
130            // logout
131            if (loginContext != null) {
132                loginContext.logout();
133            }
134        }
135    }
136
137    /**
138     * @return a plain map from a JobDataMap object
139     * @since 7.10
140     */
141    private Map<String, Serializable> getWrappedMap(JobDataMap jobMap) {
142        Map<String, Serializable> map = new HashMap<String, Serializable>();
143        for (String key : jobMap.getKeys()) {
144            map.put(key, (Serializable) jobMap.get(key));
145        }
146        return map;
147    }
148
149}