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.LoginException;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.ecm.core.api.impl.UserPrincipal;
030import org.nuxeo.ecm.core.event.Event;
031import org.nuxeo.ecm.core.event.EventContext;
032import org.nuxeo.ecm.core.event.EventService;
033import org.nuxeo.ecm.core.event.impl.EventContextImpl;
034import org.nuxeo.ecm.core.event.impl.EventImpl;
035import org.nuxeo.runtime.api.Framework;
036import org.nuxeo.runtime.api.login.LoginAs;
037import org.nuxeo.runtime.api.login.NuxeoLoginContext;
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.getService(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        try (NuxeoLoginContext loginContext = loginSystemOrUser(username)) {
092            // set up event context
093            UserPrincipal principal = new UserPrincipal(username, null, false, false);
094            EventContext eventContext = new EventContextImpl(null, principal);
095            eventContext.setProperty("category", eventCategory);
096            eventContext.setProperties(getWrappedMap(dataMap));
097            Event event = new EventImpl(eventId, eventContext);
098
099            // start transaction
100            boolean tx = TransactionHelper.startTransaction();
101
102            // send event
103            log.debug("Sending scheduled event id=" + eventId + ", category=" + eventCategory + ", username="
104                    + username);
105            boolean ok = false;
106            try {
107                eventService.fireEvent(event);
108                ok = true;
109            } finally {
110                if (tx) {
111                    if (!ok) {
112                        TransactionHelper.setTransactionRollbackOnly();
113                    }
114                    TransactionHelper.commitOrRollbackTransaction();
115                }
116            }
117        }
118    }
119
120    protected NuxeoLoginContext loginSystemOrUser(String username) throws LoginException {
121        if (username == null) {
122            return Framework.loginSystem();
123        } else {
124            if (Framework.getService(LoginAs.class) != null) {
125                return Framework.loginUser(username);
126            } else if (!Framework.isTestModeSet()) {
127                log.error("LoginAs service not available");
128            }
129            return null;
130        }
131    }
132
133    /**
134     * @return a plain map from a JobDataMap object
135     * @since 7.10
136     */
137    private Map<String, Serializable> getWrappedMap(JobDataMap jobMap) {
138        Map<String, Serializable> map = new HashMap<>();
139        for (String key : jobMap.getKeys()) {
140            map.put(key, (Serializable) jobMap.get(key));
141        }
142        return map;
143    }
144
145}