/* * Copyright 2007 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.services.blitz.impl; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import ome.api.IAdmin; import ome.api.IShare; import ome.api.local.LocalAdmin; import ome.logic.HardWiredInterceptor; import ome.services.blitz.fire.AopContextInitializer; import ome.services.blitz.fire.Registry; import ome.services.blitz.fire.TopicManager; import ome.services.blitz.util.ServiceFactoryAware; import ome.services.sessions.SessionManager; import ome.services.util.Executor; import ome.system.EventContext; import ome.system.OmeroContext; import ome.system.Principal; import ome.system.ServiceFactory; import omero.ApiUsageException; import omero.InternalException; import omero.SecurityViolation; import omero.ServerError; import omero.api.ClientCallbackPrx; import omero.api.ExporterPrx; import omero.api.ExporterPrxHelper; import omero.api.IAdminPrx; import omero.api.IAdminPrxHelper; import omero.api.IConfigPrx; import omero.api.IConfigPrxHelper; import omero.api.IContainerPrx; import omero.api.IContainerPrxHelper; import omero.api.ILdapPrx; import omero.api.ILdapPrxHelper; import omero.api.IMetadataPrx; import omero.api.IMetadataPrxHelper; import omero.api.IPixelsPrx; import omero.api.IPixelsPrxHelper; import omero.api.IProjectionPrx; import omero.api.IProjectionPrxHelper; import omero.api.IQueryPrx; import omero.api.IQueryPrxHelper; import omero.api.IRenderingSettingsPrx; import omero.api.IRenderingSettingsPrxHelper; import omero.api.IRepositoryInfoPrx; import omero.api.IRepositoryInfoPrxHelper; import omero.api.IRoiPrx; import omero.api.IRoiPrxHelper; import omero.api.IScriptPrx; import omero.api.IScriptPrxHelper; import omero.api.ISessionPrx; import omero.api.ISessionPrxHelper; import omero.api.ISharePrx; import omero.api.ISharePrxHelper; import omero.api.ITimelinePrx; import omero.api.ITimelinePrxHelper; import omero.api.ITypesPrx; import omero.api.ITypesPrxHelper; import omero.api.IUpdatePrx; import omero.api.IUpdatePrxHelper; import omero.api.JobHandlePrx; import omero.api.JobHandlePrxHelper; import omero.api.RawPixelsStorePrx; import omero.api.RawPixelsStorePrxHelper; import omero.api.RenderingEnginePrx; import omero.api.RenderingEnginePrxHelper; import omero.api.SearchPrx; import omero.api.SearchPrxHelper; import omero.api.ServiceFactoryPrx; import omero.api.ServiceFactoryPrxHelper; import omero.api.ServiceInterfacePrx; import omero.api.ServiceInterfacePrxHelper; import omero.api.StatefulServiceInterfacePrx; import omero.api.StatefulServiceInterfacePrxHelper; import omero.api.ThumbnailStorePrx; import omero.api.ThumbnailStorePrxHelper; import omero.api._ServiceFactoryOperations; import omero.constants.ADMINSERVICE; import omero.constants.CONFIGSERVICE; import omero.constants.CONTAINERSERVICE; import omero.constants.EXPORTERSERVICE; import omero.constants.JOBHANDLE; import omero.constants.LDAPSERVICE; import omero.constants.METADATASERVICE; import omero.constants.PIXELSSERVICE; import omero.constants.PROJECTIONSERVICE; import omero.constants.QUERYSERVICE; import omero.constants.RAWFILESTORE; import omero.constants.RAWPIXELSSTORE; import omero.constants.RENDERINGENGINE; import omero.constants.RENDERINGSETTINGS; import omero.constants.REPOSITORYINFO; import omero.constants.ROISERVICE; import omero.constants.SCRIPTSERVICE; import omero.constants.SEARCH; import omero.constants.SESSIONSERVICE; import omero.constants.SHAREDRESOURCES; import omero.constants.SHARESERVICE; import omero.constants.THUMBNAILSTORE; import omero.constants.TIMELINESERVICE; import omero.constants.TYPESSERVICE; import omero.constants.UPDATESERVICE; import omero.constants.topics.HEARTBEAT; import omero.grid.SharedResourcesPrx; import omero.grid.SharedResourcesPrxHelper; import omero.model.IObject; import omero.util.IceMapper; import omero.util.ServantHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.hibernate.Session; import org.springframework.transaction.annotation.Transactional; import Ice.Current; import Ice.ObjectPrx; /** * Responsible for maintaining all servants for a single session. * * In general, try to reduce access to the {@link Ice.Current} and * {@link Ice.Util} objects. * * @author Josh Moore, josh at glencoesoftware.com * @since 3.0-Beta2 */ public final class ServiceFactoryI extends omero.cmd.SessionI implements _ServiceFactoryOperations { // STATIC // =========== private final static Logger log = LoggerFactory.getLogger(ServiceFactoryI.class); // SHARED STATE // =================== // The following elements will all be the same or at least equivalent // in different instances of SF attached to the same session. final TopicManager topicManager; final Registry registry; final List<HardWiredInterceptor> cptors; final AopContextInitializer initializer; // ~ Initialization and context methods // ========================================================================= public ServiceFactoryI(Ice.Current current, ServantHolder holder, Glacier2.SessionControlPrx control, OmeroContext context, SessionManager manager, Executor executor, Principal p, List<HardWiredInterceptor> interceptors, TopicManager topicManager, Registry registry) throws ApiUsageException { this(false, current, holder, control, context, manager, executor, p, interceptors, topicManager, registry, null); } public ServiceFactoryI(boolean reusedSession, Ice.Current current, ServantHolder holder, Glacier2.SessionControlPrx control, OmeroContext context, SessionManager manager, Executor executor, Principal p, List<HardWiredInterceptor> interceptors, TopicManager topicManager, Registry registry, String token) throws ApiUsageException { super(reusedSession, current, holder, control, context, manager, executor, p, token); this.cptors = interceptors; this.initializer = new AopContextInitializer(new ServiceFactory( this.context), this.principal, this.reusedSession); this.topicManager = topicManager; this.registry = registry; } public ServiceFactoryPrx proxy() { return ServiceFactoryPrxHelper.uncheckedCast(adapter .createDirectProxy(sessionId())); } // ~ Security Context // ========================================================================= @SuppressWarnings("unchecked") public List<IObject> getSecurityContexts(Current __current) throws ServerError { final EventContext ec = getEventContext(); List<?> objs = (List) executor.execute(principal, new Executor.SimpleWork(this, "getSecurityContext") { @Transactional(readOnly = true) public Object doWork(Session session, ServiceFactory sf) { final IAdmin admin = sf.getAdminService(); final IShare share = sf.getShareService(); final List<ome.model.IObject> objs = new ArrayList<ome.model.IObject>(); // Groups final Set<Long> added = new HashSet<Long>(); for (Long id : ec.getMemberOfGroupsList()) { objs.add(admin.getGroup(id)); added.add(id); } for (Long id : ec.getLeaderOfGroupsList()) { if (!added.contains(id)) { objs.add(admin.getGroup(id)); } } // Shares objs.addAll(share.getMemberShares(true)); objs.addAll(share.getOwnShares(true)); return objs; } }); IceMapper mapper = new IceMapper(); return (List<IObject>) mapper.map(objs); } public IObject setSecurityContext(IObject obj, Current __current) throws ServerError { IceMapper mapper = new IceMapper(); try { ome.model.IObject iobj = (ome.model.IObject) mapper.reverse(obj); ome.model.IObject old = sessionManager.setSecurityContext( principal, iobj); return (IObject) mapper.map(old); } catch (Exception e) { throw handleException(e); } } public void setSecurityPassword(final String password, Current __current) throws ServerError { final EventContext ec = getEventContext(); final String name = ec.getCurrentUserName(); final boolean ok = sessionManager.executePasswordCheck(name, password); if (!ok) { final String msg = "Bad password for " + name; log.info("setSecurityPassword: " + msg); throw new SecurityViolation(null, null, "Bad password for " + name); } else { this.reusedSession.set(false); } } protected omero.ServerError handleException(Throwable t) { IceMapper mapper = new IceMapper(); Ice.UserException iue = mapper.handleException(t, context); if (iue instanceof ServerError) { return (ServerError) iue; } else { // This may not be necessary InternalException iu = new InternalException(); iu.initCause(t); IceMapper.fillServerError(iu, t); return iu; } } // ~ Stateless // ========================================================================= public IAdminPrx getAdminService(Ice.Current current) throws ServerError { return IAdminPrxHelper.uncheckedCast(getByName(ADMINSERVICE.value, current)); } public IConfigPrx getConfigService(Ice.Current current) throws ServerError { return IConfigPrxHelper.uncheckedCast(getByName(CONFIGSERVICE.value, current)); } public ILdapPrx getLdapService(Ice.Current current) throws ServerError { return ILdapPrxHelper.uncheckedCast(getByName(LDAPSERVICE.value, current)); } public IPixelsPrx getPixelsService(Ice.Current current) throws ServerError { return IPixelsPrxHelper.uncheckedCast(getByName(PIXELSSERVICE.value, current)); } public IContainerPrx getContainerService(Ice.Current current) throws ServerError { return IContainerPrxHelper.uncheckedCast(getByName( CONTAINERSERVICE.value, current)); } public IProjectionPrx getProjectionService(Ice.Current current) throws ServerError { return IProjectionPrxHelper.uncheckedCast(getByName( PROJECTIONSERVICE.value, current)); } public IQueryPrx getQueryService(Ice.Current current) throws ServerError { return IQueryPrxHelper.uncheckedCast(getByName(QUERYSERVICE.value, current)); } public IRoiPrx getRoiService(Ice.Current current) throws ServerError { Ice.ObjectPrx prx = getByName(ROISERVICE.value, current); return IRoiPrxHelper.uncheckedCast(prx); } public IScriptPrx getScriptService(Ice.Current current) throws ServerError { Ice.ObjectPrx prx = getByName(SCRIPTSERVICE.value, current); return IScriptPrxHelper.uncheckedCast(prx); } public ISessionPrx getSessionService(Current current) throws ServerError { return ISessionPrxHelper.uncheckedCast(getByName(SESSIONSERVICE.value, current)); } public ISharePrx getShareService(Current current) throws ServerError { return ISharePrxHelper.uncheckedCast(getByName(SHARESERVICE.value, current)); } public ITimelinePrx getTimelineService(Ice.Current current) throws ServerError { return ITimelinePrxHelper.uncheckedCast(getByName( TIMELINESERVICE.value, current)); } public ITypesPrx getTypesService(Ice.Current current) throws ServerError { return ITypesPrxHelper.uncheckedCast(getByName(TYPESSERVICE.value, current)); } public IUpdatePrx getUpdateService(Ice.Current current) throws ServerError { Ice.ObjectPrx prx = getByName(UPDATESERVICE.value, current); return IUpdatePrxHelper.uncheckedCast(prx); } public IRenderingSettingsPrx getRenderingSettingsService(Ice.Current current) throws ServerError { return IRenderingSettingsPrxHelper.uncheckedCast(getByName( RENDERINGSETTINGS.value, current)); } public IRepositoryInfoPrx getRepositoryInfoService(Ice.Current current) throws ServerError { return IRepositoryInfoPrxHelper.uncheckedCast(getByName( REPOSITORYINFO.value, current)); } public IMetadataPrx getMetadataService(Ice.Current current) throws ServerError { return IMetadataPrxHelper.uncheckedCast(getByName( METADATASERVICE.value, current)); } // ~ Stateful // ========================================================================= public ExporterPrx createExporter(Current current) throws ServerError { return ExporterPrxHelper.uncheckedCast(createByName( EXPORTERSERVICE.value, current)); } public JobHandlePrx createJobHandle(Ice.Current current) throws ServerError { return JobHandlePrxHelper.uncheckedCast(createByName(JOBHANDLE.value, current)); } public RenderingEnginePrx createRenderingEngine(Ice.Current current) throws ServerError { return RenderingEnginePrxHelper.uncheckedCast(createByName( RENDERINGENGINE.value, current)); } public omero.api.RawFileStorePrx createRawFileStore(Ice.Current current) throws ServerError { return omero.api.RawFileStorePrxHelper.uncheckedCast(createByName( RAWFILESTORE.value, current)); } public RawPixelsStorePrx createRawPixelsStore(Ice.Current current) throws ServerError { return RawPixelsStorePrxHelper.uncheckedCast(createByName( RAWPIXELSSTORE.value, current)); } public SearchPrx createSearchService(Ice.Current current) throws ServerError { return SearchPrxHelper .uncheckedCast(createByName(SEARCH.value, current)); } public ThumbnailStorePrx createThumbnailStore(Ice.Current current) throws ServerError { return ThumbnailStorePrxHelper.uncheckedCast(createByName( THUMBNAILSTORE.value, current)); } // ~ Other interface methods // ========================================================================= public SharedResourcesPrx sharedResources(Current current) throws ServerError { return SharedResourcesPrxHelper.uncheckedCast(getByName( SHAREDRESOURCES.value, current)); } public Ice.TieBase getTie(Ice.Identity id) { return (Ice.TieBase) holder.get(id); } public Object getServant(Ice.Identity id) { return holder.getUntied(id); } public ServiceInterfacePrx getByName(String blankname, Current dontUse) throws ServerError { // First try to get the blankname as is in case a value from // activeServices is being passed back in. Ice.Identity immediateId = holder.getIdentity(blankname); if (holder.get(immediateId) != null) { return ServiceInterfacePrxHelper.uncheckedCast(adapter .createDirectProxy(immediateId)); } // ticket:911 - in order to use a different initializer // for each stateless service, we need to attach modify the id. // idName is just the value id.name not Ice.Util.identityToString(id) String idName = clientId + blankname; Ice.Identity id = holder.getIdentity(idName); holder.acquireLock(idName); try { Ice.ObjectPrx prx; Ice.Object servant = holder.get(id); if (servant == null) { servant = createServantDelegate(blankname); // Previously we checked for stateful services here, // however the logic is the same so it shouldn't // cause any issues. prx = registerServant(id, servant); } else { prx = adapter.createDirectProxy(id); } return ServiceInterfacePrxHelper.uncheckedCast(prx); } finally { holder.releaseLock(idName); } } public StatefulServiceInterfacePrx createByName(String name, Current current) throws ServerError { Ice.Identity id = holder.getIdentity(UUID.randomUUID().toString() + name); if (null != adapter.find(id)) { omero.InternalException ie = new omero.InternalException(); ie.message = name + " already registered for this adapter."; } Ice.Object servant = createServantDelegate(name); Ice.ObjectPrx prx = registerServant(id, servant); return StatefulServiceInterfacePrxHelper.uncheckedCast(prx); } public void subscribe(String topicName, ObjectPrx prx, Current __current) throws ServerError { if (topicName == null || !topicName.startsWith("/public/")) { throw new omero.ApiUsageException(null, null, "Currently only \"/public/\" topics allowed."); } topicManager.register(topicName, prx, false); log.info("Registered " + prx + " for " + topicName); } public void setCallback(ClientCallbackPrx callback, Ice.Current current) throws ServerError { if (false) { // ticket:2558, disabling because of long logins. See also // #2485 this.callback = callback; log.info(Ice.Util.identityToString(this.sessionId()) + " set callback to " + this.callback); try { subscribe(HEARTBEAT.value, callback, current); // ticket:2485. Ignoring any errors on registration // of callbacks to permit login. Other client // callbacks may want to force an exception with ice_isA // or similar. } catch (RuntimeException e) { log.warn("Failed to subscribe " + callback, e); // throw e; ticket:2485 } catch (ServerError e) { log.warn("Failed to subscribe " + callback, e); // throw e; ticket:2485 } catch (Exception e) { log.warn("Failed to subscribe " + callback, e); // throw new RuntimeException(e); ticket:2485 } } } public void detachOnDestroy(Ice.Current current) { doClose = false; } @Deprecated public void close(Ice.Current current) { doClose = false; } public void closeOnDestroy(Ice.Current current) { doClose = true; } /** * NB: Much of the logic here is similar to {@link #doClose} and should be * pushed down. */ public String getStatefulServiceCount() { return holder.getStatefulServiceCount(); } public List<String> activeServices(Current __current) { return holder.getServantList(); } /** Doesn't take current into account */ public EventContext getEventContext() { return sessionManager.getEventContext(this.principal); } /** Takes current into account */ public EventContext getEventContext(final Ice.Current current) { return (EventContext) executor.execute(current.ctx, this.principal, new Executor.SimpleWork(this, "getEventContext") { @Transactional(readOnly=true) public Object doWork(Session session, ServiceFactory sf) { return ((LocalAdmin) sf.getAdminService()).getEventContextQuiet(); } }); } public long keepAllAlive(ServiceInterfacePrx[] proxies, Current __current) throws ServerError { try { // First take measures to keep the session alive getEventContext(); if (log.isDebugEnabled()) { log.debug("Keep all alive: " + this); } if (proxies == null || proxies.length == 0) { return -1; // All set to 1 } long retVal = 0; for (int i = 0; i < proxies.length; i++) { ServiceInterfacePrx prx = proxies[i]; if (prx == null) { continue; } Ice.Identity id = prx.ice_getIdentity(); if (null == holder.get(id)) { retVal |= 1 << i; } } return retVal; } catch (Throwable t) { throw handleException(t); } } /** * Currently ignoring the individual proxies */ public boolean keepAlive(ServiceInterfacePrx proxy, Current __current) throws ServerError { try { // First take measures to keep the session alive getEventContext(); if (log.isDebugEnabled()) { log.debug("Keep alive: " + this); } if (proxy == null) { return false; } Ice.Identity id = proxy.ice_getIdentity(); return null != holder.get(id); } catch (Throwable t) { throw handleException(t); } } // ~ Helpers // ========================================================================= @Override protected void internalServantConfig(Object obj) throws ServerError { super.internalServantConfig(obj); if (obj instanceof ServiceFactoryAware) { ((ServiceFactoryAware) obj).setServiceFactory(this); } if (obj instanceof AbstractAmdServant) { AbstractAmdServant amd = (AbstractAmdServant) obj; amd.applyHardWiredInterceptors(cptors, initializer); amd.setHolder(holder); // TODO: amd.setApplicationContext(context); } } }