/* * © Copyright IBM Corp. 2010 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package nsf.playground.jobs; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Date; import java.util.HashMap; import java.util.Map; import lotus.domino.NotesException; import lotus.domino.Session; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import com.ibm.commons.Platform; import com.ibm.commons.util.StringUtil; import com.ibm.domino.xsp.module.nsf.ThreadSessionExecutor; import com.ibm.jscript.InterpretException; import com.ibm.jscript.std.ObjectObject; import com.ibm.jscript.types.FBSBoolean; import com.ibm.jscript.types.FBSNull; import com.ibm.jscript.types.FBSNumber; import com.ibm.jscript.types.FBSString; import com.ibm.jscript.types.FBSUtility; import com.ibm.jscript.types.FBSValue; import com.ibm.xsp.extlib.util.ExtLibUtil; /** * Base class for application related asynchronous actions. */ public abstract class AsyncAction { private static final String ASYNC_KEY = "_asyncAction"; @SuppressWarnings("unchecked") public static synchronized Map<String,AsyncAction> getActions() { Map<String,AsyncAction> map = (Map<String,AsyncAction>)ExtLibUtil.getApplicationScope().get(ASYNC_KEY); if(map==null) { map = new HashMap<String,AsyncAction>(); ExtLibUtil.getApplicationScope().put(ASYNC_KEY,map); } return map; } public static synchronized void registerAction(String actionId, AsyncAction action) { getActions().put(actionId,action); } public static synchronized boolean actionExists(String actionId) { AsyncAction action = getActions().get(actionId); return action!=null; } public static synchronized AsyncAction getAction(String actionId) { AsyncAction action = getActions().get(actionId); return action; } public static synchronized boolean isActionRunning(String actionId) { AsyncAction action = getActions().get(actionId); return action!=null && action.isRunning(); } public static synchronized boolean isActionCancelled(String actionId) { AsyncAction action = getActions().get(actionId); return action!=null && action.isCancelled(); } public static synchronized boolean cancel(String actionId) { AsyncAction action = getActions().get(actionId); if(action!=null) { action.cancelAction(); return true; } return false; } public static boolean runAction(String actionId) { return runAction(actionId, null); } public static synchronized boolean runAction(String actionId, Object parameters) { AsyncAction action = getActions().get(actionId); if(action!=null) { return runAction(action,parameters); } return false; } public static synchronized boolean runAction(final AsyncAction action, final Object parameters) { // Do not start if it is already running if(action!=null && action.isRunning()) { return false; } ThreadSessionExecutor<IStatus> executor = new ThreadSessionExecutor<IStatus>() { @Override protected IStatus run(Session session) throws NotesException { //testSecurity("c:\\threadexec2.txt"); action.running = true; action.cancelled = false; action.runCount++; try { action.run(session,parameters); return action.isCancelled() ? Status.CANCEL_STATUS : Status.OK_STATUS; } finally { action.running = false; // /runningJobs.remove(jobId); } } }; final InternalEclipseJob newJob = new InternalEclipseJob(action,executor); AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { newJob.schedule(); return null; } }); return true; } public static synchronized FBSValue getJobProgressJavaScript(String jobId) { try { AsyncAction action = getActions().get(jobId); if(action!=null) { synchronized(action) { ObjectObject o = new ObjectObject(); o.put("exists", FBSBoolean.TRUE); o.put("running", FBSUtility.wrap(action.isRunning())); o.put("runCount", FBSUtility.wrap(action.getRunCount())); o.put("statusTs", FBSUtility.wrap(action.getStatusTs())); o.put("cancelled", FBSUtility.wrap(action.isCancelled())); o.put("label", FBSUtility.wrap(action.getActionLabel())); o.put("taskLabel", FBSUtility.wrap(action.getTaskLabel())); o.put("taskCompletion", FBSUtility.wrap(action.getTaskCompletion())); o.put("fullCompletion", FBSUtility.wrap(action.getTotalCompletion())); return o; } } else { ObjectObject o = new ObjectObject(); o.put("exists", FBSBoolean.FALSE); o.put("running", FBSBoolean.FALSE); o.put("runCount", FBSNumber.Zero); o.put("cancelled", FBSBoolean.FALSE); o.put("statusTs", FBSNumber.Zero); o.put("label", FBSString.emptyString); o.put("taskLabel", FBSString.emptyString); o.put("taskCompletion", FBSNumber.Zero); o.put("fullCompletion", FBSNumber.Zero); return o; } } catch(InterpretException ex) { Platform.getInstance().log(ex); } return FBSNull.nullValue; } private static final class InternalEclipseJob extends Job { private AsyncAction action; private ThreadSessionExecutor<IStatus> executor; public InternalEclipseJob(final AsyncAction action, ThreadSessionExecutor<IStatus> executor) { super(action.getActionLabel()); this.action = action; this.executor = executor; } protected final IStatus run(IProgressMonitor monitor) { try { return executor.run(); } catch(Exception ex) { return Status.CANCEL_STATUS; } } }; private boolean running; private boolean cancelled; private String task; private int taskCompletion; private int completion; private int runCount; private long statusTs; public AsyncAction() { } public boolean isRunning() { return running; } public boolean isCancelled() { return cancelled; } public long getStatusTs() { return statusTs; } public void cancelAction() { this.cancelled = true; this.completion = 100; this.taskCompletion = 0; this.task = "Action cancelled by user"; this.statusTs = System.currentTimeMillis(); } public String getTaskLabel() { return task; } public int getTaskCompletion() { return taskCompletion; } public int getTotalCompletion() { return completion; } public int getRunCount() { return runCount; } public synchronized void updateTask(String msg, Object...params) { if(!cancelled) { this.task = StringUtil.format(msg,params); this.taskCompletion = 0; this.statusTs = System.currentTimeMillis(); } } public synchronized void updateCompletion(int task, int completion) { if(!cancelled) { this.taskCompletion = task; this.completion = completion; this.statusTs = System.currentTimeMillis(); } } public synchronized void updateException(Throwable t) { this.task = t.getMessage(); this.completion = 100; this.taskCompletion = 0; this.cancelled = true; this.statusTs = System.currentTimeMillis(); } public synchronized void updateException(Throwable t, String msg, Object...params) { this.task = StringUtil.format(msg,params)+"\n"+t.getMessage(); this.completion = 100; this.taskCompletion = 0; this.cancelled = true; this.statusTs = System.currentTimeMillis(); } // Helpers... public static int muldiv(int a, int b, int div) { return (int)((long)a*(long)b/(long)div); } // // Required methods // public abstract String getActionLabel(); public abstract void run(Session session, Object parameters) throws NotesException; // Quick security manager test protected void testSecurity(String fileName) { File f = new File(fileName); try { //SecurityManager sm = System.getSecurityManager(); FileWriter fw = new FileWriter(f); fw.write("TEST WRITING A FILE, "+(new Date()).toString()); fw.close(); } catch(IOException io) {io.printStackTrace();} } }