root/trunk/components/server/src/ome/logic/UpdateImpl.java
| Revision 2495, 10.8 kB (checked in by jmoore, 7 months ago) | |
|---|---|
|
|
| Line | |
|---|---|
| 1 | /* |
| 2 | * ome.logic.UpdateImpl |
| 3 | * |
| 4 | * Copyright 2006 University of Dundee. All rights reserved. |
| 5 | * Use is subject to license terms supplied in LICENSE.txt |
| 6 | */ |
| 7 | |
| 8 | /*------------------------------------------------------------------------------ |
| 9 | * |
| 10 | * Written by: Josh Moore <josh.moore@gmx.de> |
| 11 | * |
| 12 | *------------------------------------------------------------------------------ |
| 13 | */ |
| 14 | |
| 15 | package ome.logic; |
| 16 | |
| 17 | // Java imports |
| 18 | import java.sql.SQLException; |
| 19 | import java.util.Collection; |
| 20 | |
| 21 | import javax.annotation.security.RolesAllowed; |
| 22 | import javax.ejb.Local; |
| 23 | import javax.ejb.Remote; |
| 24 | import javax.ejb.Stateless; |
| 25 | import javax.ejb.TransactionManagement; |
| 26 | import javax.ejb.TransactionManagementType; |
| 27 | import javax.interceptor.Interceptors; |
| 28 | |
| 29 | import ome.api.IUpdate; |
| 30 | import ome.api.ServiceInterface; |
| 31 | import ome.api.local.LocalQuery; |
| 32 | import ome.api.local.LocalUpdate; |
| 33 | import ome.conditions.ApiUsageException; |
| 34 | import ome.conditions.ValidationException; |
| 35 | import ome.model.IObject; |
| 36 | import ome.model.meta.EventLog; |
| 37 | import ome.parameters.Parameters; |
| 38 | import ome.services.fulltext.EventLogLoader; |
| 39 | import ome.services.fulltext.FullTextBridge; |
| 40 | import ome.services.fulltext.FullTextIndexer; |
| 41 | import ome.services.fulltext.FullTextThread; |
| 42 | import ome.services.sessions.SessionManager; |
| 43 | import ome.services.util.Executor; |
| 44 | import ome.services.util.OmeroAroundInvoke; |
| 45 | import ome.tools.hibernate.UpdateFilter; |
| 46 | import ome.util.Utils; |
| 47 | |
| 48 | import org.hibernate.HibernateException; |
| 49 | import org.hibernate.Session; |
| 50 | import org.jboss.annotation.ejb.LocalBinding; |
| 51 | import org.jboss.annotation.ejb.RemoteBinding; |
| 52 | import org.jboss.annotation.ejb.RemoteBindings; |
| 53 | import org.springframework.orm.hibernate3.HibernateCallback; |
| 54 | import org.springframework.transaction.annotation.Transactional; |
| 55 | |
| 56 | /** |
| 57 | * implementation of the IUpdate service interface |
| 58 | * |
| 59 | * @author Josh Moore, <a href="mailto:josh.moore@gmx.de">josh.moore@gmx.de</a> |
| 60 | * @version 1.0 <small> (<b>Internal version:</b> $Rev$ $Date$) </small> |
| 61 | * @since OMERO 3.0 |
| 62 | */ |
| 63 | @TransactionManagement(TransactionManagementType.BEAN) |
| 64 | @Transactional(readOnly = false) |
| 65 | @Stateless |
| 66 | @Remote(IUpdate.class) |
| 67 | @RemoteBindings( { |
| 68 | @RemoteBinding(jndiBinding = "omero/remote/ome.api.IUpdate"), |
| 69 | @RemoteBinding(jndiBinding = "omero/secure/ome.api.IUpdate", clientBindUrl = "sslsocket://0.0.0.0:3843") }) |
| 70 | @Local(LocalUpdate.class) |
| 71 | @LocalBinding(jndiBinding = "omero/local/ome.api.local.LocalUpdate") |
| 72 | @Interceptors( { OmeroAroundInvoke.class, SimpleLifecycle.class }) |
| 73 | public class UpdateImpl extends AbstractLevel1Service implements LocalUpdate { |
| 74 | |
| 75 | protected transient LocalQuery localQuery; |
| 76 | |
| 77 | protected transient Executor executor; |
| 78 | |
| 79 | protected transient SessionManager sessionManager; |
| 80 | |
| 81 | protected transient FullTextBridge fullTextBridge; |
| 82 | |
| 83 | public final void setQueryService(LocalQuery query) { |
| 84 | getBeanHelper().throwIfAlreadySet(this.localQuery, query); |
| 85 | this.localQuery = query; |
| 86 | } |
| 87 | |
| 88 | public void setExecutor(Executor executor) { |
| 89 | getBeanHelper().throwIfAlreadySet(this.executor, executor); |
| 90 | this.executor = executor; |
| 91 | } |
| 92 | |
| 93 | public void setSessionManager(SessionManager sessionManager) { |
| 94 | getBeanHelper().throwIfAlreadySet(this.sessionManager, sessionManager); |
| 95 | this.sessionManager = sessionManager; |
| 96 | } |
| 97 | |
| 98 | public void setFullTextBridge(FullTextBridge fullTextBridge) { |
| 99 | getBeanHelper().throwIfAlreadySet(this.fullTextBridge, fullTextBridge); |
| 100 | this.fullTextBridge = fullTextBridge; |
| 101 | } |
| 102 | |
| 103 | public Class<? extends ServiceInterface> getServiceInterface() { |
| 104 | return IUpdate.class; |
| 105 | }; |
| 106 | |
| 107 | // ~ LOCAL PUBLIC METHODS |
| 108 | // ========================================================================= |
| 109 | |
| 110 | @RolesAllowed("user") |
| 111 | public void rollback() { |
| 112 | getHibernateTemplate().execute(new HibernateCallback() { |
| 113 | public Object doInHibernate(Session session) |
| 114 | throws HibernateException, SQLException { |
| 115 | session.connection().rollback(); |
| 116 | return null; |
| 117 | }; |
| 118 | }); |
| 119 | } |
| 120 | |
| 121 | @RolesAllowed("user") |
| 122 | public void flush() { |
| 123 | getHibernateTemplate().execute(new HibernateCallback() { |
| 124 | public Object doInHibernate(Session session) |
| 125 | throws HibernateException, SQLException { |
| 126 | session.flush(); |
| 127 | return null; |
| 128 | }; |
| 129 | }); |
| 130 | } |
| 131 | |
| 132 | @RolesAllowed("user") |
| 133 | public void commit() { |
| 134 | getHibernateTemplate().execute(new HibernateCallback() { |
| 135 | public Object doInHibernate(Session session) |
| 136 | throws HibernateException, SQLException { |
| 137 | session.connection().commit(); |
| 138 | return null; |
| 139 | }; |
| 140 | }); |
| 141 | } |
| 142 | |
| 143 | // ~ INTERFACE METHODS |
| 144 | // ========================================================================= |
| 145 | |
| 146 | @RolesAllowed("user") |
| 147 | public void saveObject(IObject graph) { |
| 148 | doAction(graph, new UpdateAction<IObject>() { |
| 149 | @Override |
| 150 | public IObject run(IObject value, UpdateFilter filter) { |
| 151 | return internalSave(value, filter); |
| 152 | } |
| 153 | }); |
| 154 | } |
| 155 | |
| 156 | @RolesAllowed("user") |
| 157 | public IObject saveAndReturnObject(IObject graph) { |
| 158 | return doAction(graph, new UpdateAction<IObject>() { |
| 159 | @Override |
| 160 | public IObject run(IObject value, UpdateFilter filter) { |
| 161 | return internalSave(value, filter); |
| 162 | } |
| 163 | }); |
| 164 | } |
| 165 | |
| 166 | @RolesAllowed("user") |
| 167 | public void saveCollection(Collection graph) { |
| 168 | doAction(graph, new UpdateAction<Collection>() { |
| 169 | @Override |
| 170 | public Collection run(Collection value, UpdateFilter filter) { |
| 171 | for (Object o : value) { |
| 172 | IObject obj = (IObject) o; |
| 173 | obj = internalSave(obj, filter); |
| 174 | } |
| 175 | return null; |
| 176 | } |
| 177 | }); |
| 178 | } |
| 179 | |
| 180 | @RolesAllowed("user") |
| 181 | public IObject[] saveAndReturnArray(IObject[] graph) { |
| 182 | return doAction(graph, new UpdateAction<IObject[]>() { |
| 183 | @Override |
| 184 | public IObject[] run(IObject[] value, UpdateFilter filter) { |
| 185 | IObject[] copy = new IObject[value.length]; |
| 186 | for (int i = 0; i < value.length; i++) { |
| 187 | copy[i] = internalSave(value[i], filter); |
| 188 | } |
| 189 | return copy; |
| 190 | } |
| 191 | }); |
| 192 | } |
| 193 | |
| 194 | @RolesAllowed("user") |
| 195 | public void saveArray(IObject[] graph) { |
| 196 | doAction(graph, new UpdateAction<IObject[]>() { |
| 197 | @Override |
| 198 | public IObject[] run(IObject[] value, UpdateFilter filter) { |
| 199 | IObject[] copy = new IObject[value.length]; |
| 200 | for (int i = 0; i < value.length; i++) { |
| 201 | copy[i] = internalSave(value[i], filter); |
| 202 | } |
| 203 | return copy; |
| 204 | } |
| 205 | }); |
| 206 | } |
| 207 | |
| 208 | @RolesAllowed("user") |
| 209 | public void deleteObject(IObject row) { |
| 210 | if (row == null) { |
| 211 | return; |
| 212 | } |
| 213 | if (row.getId() == null) { |
| 214 | throw new ApiUsageException( |
| 215 | "Non-managed IObject entity cannot be deleted. Must have an id."); |
| 216 | } |
| 217 | doAction(row, new UpdateAction<IObject>() { |
| 218 | @Override |
| 219 | public IObject run(IObject value, UpdateFilter filter) { |
| 220 | internalDelete(value, filter); |
| 221 | return null; |
| 222 | } |
| 223 | }); |
| 224 | } |
| 225 | |
| 226 | @RolesAllowed("system") |
| 227 | public void indexObject(IObject row) { |
| 228 | if (row == null || row.getId() == null) { |
| 229 | throw new ValidationException( |
| 230 | "Non-managed object canoot be indexed."); |
| 231 | } |
| 232 | |
| 233 | CreationLogLoader logs = new CreationLogLoader(localQuery, row); |
| 234 | FullTextIndexer fti = new FullTextIndexer(logs); |
| 235 | FullTextThread ftt = new FullTextThread(sessionManager, executor, fti, |
| 236 | this.fullTextBridge, true); |
| 237 | ftt.run(); |
| 238 | } |
| 239 | |
| 240 | // ~ Internals |
| 241 | // ========================================================= |
| 242 | private void beforeUpdate(Object argument, UpdateFilter filter) { |
| 243 | |
| 244 | if (argument == null) { |
| 245 | throw new IllegalArgumentException( |
| 246 | "Argument to save cannot be null."); |
| 247 | } |
| 248 | |
| 249 | if (getBeanHelper().getLogger().isDebugEnabled()) { |
| 250 | getBeanHelper().getLogger().debug(" Saving event before merge. "); |
| 251 | } |
| 252 | |
| 253 | } |
| 254 | |
| 255 | /** |
| 256 | * Note if we use anything other than merge here, functionality from |
| 257 | * {@link ome.tools.hibernate.MergeEventListener} needs to be moved to |
| 258 | * {@link UpdateFilter} or to another event listener. |
| 259 | */ |
| 260 | protected IObject internalSave(IObject obj, UpdateFilter filter) { |
| 261 | if (getBeanHelper().getLogger().isDebugEnabled()) { |
| 262 | getBeanHelper().getLogger().debug(" Internal save. "); |
| 263 | } |
| 264 | |
| 265 | IObject result = (IObject) filter.filter(null, obj); |
| 266 | result = (IObject) getHibernateTemplate().merge(result); |
| 267 | return result; |
| 268 | } |
| 269 | |
| 270 | protected void internalDelete(IObject obj, UpdateFilter filter) { |
| 271 | if (getBeanHelper().getLogger().isDebugEnabled()) { |
| 272 | getBeanHelper().getLogger().debug(" Internal delete. "); |
| 273 | } |
| 274 | |
| 275 | getHibernateTemplate().delete( |
| 276 | getHibernateTemplate().load(Utils.trueClass(obj.getClass()), |
| 277 | obj.getId())); |
| 278 | } |
| 279 | |
| 280 | private void afterUpdate(UpdateFilter filter) { |
| 281 | |
| 282 | if (getBeanHelper().getLogger().isDebugEnabled()) { |
| 283 | getBeanHelper().getLogger().debug(" Post-save cleanup. "); |
| 284 | } |
| 285 | |
| 286 | // Clean up |
| 287 | getHibernateTemplate().flush(); |
| 288 | filter.unloadReplacedObjects(); |
| 289 | |
| 290 | } |
| 291 | |
| 292 | private <T> T doAction(T graph, UpdateAction<T> action) { |
| 293 | T retVal; |
| 294 | UpdateFilter filter = new UpdateFilter(); |
| 295 | try { |
| 296 | beforeUpdate(graph, filter); |
| 297 | retVal = action.run(graph, filter); |
| 298 | afterUpdate(filter); |
| 299 | } finally { |
| 300 | // currently nothing. |
| 301 | } |
| 302 | return retVal; |
| 303 | } |
| 304 | |
| 305 | private abstract class UpdateAction<T> { |
| 306 | public abstract T run(T value, UpdateFilter filter); |
| 307 | } |
| 308 | |
| 309 | } |
| 310 | |
| 311 | /** |
| 312 | * {@link EventLogLoader} which loads a single instance. |
| 313 | */ |
| 314 | class CreationLogLoader extends EventLogLoader { |
| 315 | |
| 316 | final private LocalQuery query; |
| 317 | |
| 318 | private IObject obj; |
| 319 | |
| 320 | public CreationLogLoader(LocalQuery query, IObject obj) { |
| 321 | this.query = query; |
| 322 | this.obj = obj; |
| 323 | } |
| 324 | |
| 325 | @Override |
| 326 | public EventLog query() { |
| 327 | if (obj == null) { |
| 328 | return null; |
| 329 | } else { |
| 330 | EventLog el = query.findByQuery("select el from EventLog el " |
| 331 | + "where el.action = 'INSERT' and " |
| 332 | + "el.entityType = :type and " + "el.entityId = :id", |
| 333 | new Parameters() |
| 334 | .addString("type", obj.getClass().getName()).addId( |
| 335 | obj.getId())); |
| 336 | obj = null; |
| 337 | return el; |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | @Override |
| 342 | public long more() { |
| 343 | return 0; |
| 344 | } |
| 345 | |
| 346 | } |
Note: See TracBrowser
for help on using the browser.
