/* * $Id$ * * Copyright 2010 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package omero.grid; import ome.parameters.Parameters; import ome.security.AdminAction; import ome.security.SecuritySystem; import ome.services.util.Executor; import ome.services.util.IceUtil; import ome.system.Principal; import ome.system.ServiceFactory; import omero.InternalException; import omero.ServerError; import omero.model.Job; import omero.model.OriginalFileI; import omero.model.ParseJob; import omero.model.ParseJobI; import org.hibernate.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.annotation.Transactional; import Ice.Current; import Ice.ReadObjectCallback; import Ice.UnmarshalOutOfBoundsException; /** * * * @since Beta4.2 */ public class ParamsHelper { private final static Logger log = LoggerFactory.getLogger(ParamsHelper.class); private final Acquirer acq; private final Executor ex; private final Principal p; private final SecuritySystem secSys; public ParamsHelper(Acquirer acq, Executor ex, Principal p) { this.acq = acq; this.ex = ex; this.p = p; this.secSys = // FIXME REFACTOR (SecuritySystem) ex.getContext().getBean("securitySystem"); } // // HELPER // /** * Build a job for the script with id. * * @param id * script id. * @return the job. * @throws ServerError if the job could not be built for the script */ public ParseJobI buildParseJob(final long id) throws ServerError { final OriginalFileI file = new OriginalFileI(id, false); final ParseJobI job = new ParseJobI(); job.linkOriginalFile(file); job.setMessage(omero.rtypes.rstring(String.format("Parsing script %s", id))); return job; } /** * Get the script params for the file. * * @param id * the ID of the script * @param __current * regarding the method invocation * @return jobparams of the script. * @throws ServerError if the params could not be retrieved or created */ public JobParams getOrCreateParams(final long id, Current __current) throws ServerError { JobParams params = getParamsOrNull(id, __current); if (params == null) { return generateScriptParams(id, __current); } return params; } JobParams getParamsOrNull(final long scriptId, Current __current) { ome.model.jobs.ParseJob job = getParseJobForScript(scriptId, __current); if (job != null) { return parse(job.getParams(), __current); } return null; } ome.model.jobs.ParseJob getParseJobForScript(final long scriptId, final Ice.Current current) { ome.model.jobs.ParseJob job = (ome.model.jobs.ParseJob) ex.execute(current.ctx, p, new Executor.SimpleWork(this, "getParseJobForScript", scriptId) { @Transactional(readOnly = true) public Object doWork(Session session, ServiceFactory sf) { Parameters p = new Parameters(); p.page(0, 1); p.addLong("id", scriptId); return sf .getQueryService() .findByQuery( "select job from ParseJob job " + "join job.originalFileLinks scriptlinks " + "join scriptlinks.child script " + "where job.params is not null " + "and script.id = :id " + "and script.details.updateEvent.id <= job.details.updateEvent.id " + "order by job.details.updateEvent.id desc", p); } }); return job; } JobParams generateScriptParams(long id, Ice.Current __current) throws ServerError { return generateScriptParams(id, true, __current); } /** * Acquires an {@link InteractiveProcessorPrx} and runs a {@link ParseJob}. * If the "save" argument is true, then the {@link JobParams} instance will * be saved to the database; otherwise, the {@link ParseJob} will be deleted. */ public JobParams generateScriptParams(long id, boolean save, Ice.Current __current) throws ServerError { ParseJob job = buildParseJob(id); InteractiveProcessorPrx proc = acq.acquireProcessor(job, 10, __current); if (proc == null) { throw new InternalException(null, null, "No processor acquired."); } job = (ParseJob) proc.getJob(__current.ctx); final JobParams rv = proc.params(__current.ctx); if (save) { // Guaranteed non-null for a parse job saveScriptParams(rv, job, __current); } else { deleteScriptParams(job, __current); } return rv; } void saveScriptParams(JobParams params, final ParseJob job, Ice.Current __current) throws ServerError { final byte[] data = parse(params, __current); ex.execute(__current.ctx, p, new Executor.SimpleWork(this, "saveScriptParams", job.getId().getValue()) { @Transactional(readOnly = false) public Object doWork(final Session session, final ServiceFactory sf) { ome.model.jobs.ParseJob parseJob = sf.getQueryService().get( ome.model.jobs.ParseJob.class, job.getId().getValue()); parseJob.setParams(data); secSys.runAsAdmin(new AdminAction(){ public void runAsAdmin() { session.flush(); }}); return null; } }); } void deleteScriptParams(final ParseJob job, Ice.Current __current) throws ServerError { ex.execute(__current.ctx, p, new Executor.SimpleWork(this, "deleteScriptParams", job.getId().getValue()) { @Transactional(readOnly = false) public Object doWork(final Session session, final ServiceFactory sf) { final ome.model.jobs.ParseJob parseJob = sf.getQueryService().get( ome.model.jobs.ParseJob.class, job.getId().getValue()); secSys.runAsAdmin(new AdminAction(){ public void runAsAdmin() { session.delete(parseJob); session.flush(); }}); return null; } }); } byte[] parse(JobParams params, Ice.Current current) { Ice.OutputStream os = IceUtil.createSafeOutputStream( current.adapter.getCommunicator()); byte[] bytes = null; try { os.writeObject(params); os.writePendingObjects(); bytes = os.finished(); } finally { os.destroy(); } return bytes; } JobParams parse(byte[] data, Ice.Current current) { if (data == null) { return null; // EARLY EXIT! } Ice.InputStream is = IceUtil.createSafeInputStream( current.adapter.getCommunicator(), data); final JobParams[] params = new JobParams[1]; try { is.readObject(new ReadObjectCallback() { public void invoke(Ice.Object arg0) { params[0] = (JobParams) arg0; } }); is.readPendingObjects(); } catch (UnmarshalOutOfBoundsException oob) { // ok, returning null. } catch (Ice.MarshalException me) { // less specific than oob; not great, but returning null. #5662 log.error(String.format("MarshalException: %s (len=%s)", me.reason, data.length)); } catch (OutOfMemoryError oom) { // Not ok, but not much we can do. // This is caused by changes to slice files. // See: log.warn("http://www.zeroc.com/forums/bug-reports/4782-3-3-1-outofmemory-client-when-slice-definition-modified.html"); } finally { is.destroy(); } return params[0]; } /** * Interface added in order to allow ParamHelper instances to use methods * from SharedResourcesI. The build does not allow for a dependency between * the two. */ // TODO refactor public interface Acquirer { public InteractiveProcessorPrx acquireProcessor(final Job submittedJob, int seconds, final Current current) throws ServerError; } }