Hi Oscar

Although we probably won't use this in Estatio, it is (I think) a valid use
case.

We do in fact have a ticket for it already, ISIS-803 [1].  And the original
ticket that introduced the event bus, ISIS-550 [2], although it didn't
implement the feature, did mention it.

In a similar vein, if we implement ISIS-803 then I think the recently
raised ISIS-1005 [3] is probably redundant (or at least, is part of
ISIS-803).

In terms of priorities, I want to get my @Action / @Property / @Collection
stuff finished off.  Then I'll take a look at this and see how much work it
is to squeeze in for 1.8.0 or not.

HTH
Dan


[1] https://issues.apache.org/jira/browse/ISIS-803
[2] https://issues.apache.org/jira/browse/ISIS-550
[3] https://issues.apache.org/jira/browse/ISIS-1005


~~~~~~~~~~~~~


On 13 January 2015 at 14:06, GESCONSULTOR - Óscar Bou <
[email protected]> wrote:

> Hi, Dan and Jeroen for your pointing me towards those examples.
>
> As I'm seeing on Estatio, event publishing is made through an
> @ActionInteraction annotation, which requires to always delete entities by
> means of that action.
>
> I attached the event post to the "removing" framework method for
> publishing the event every time an object is going to be delete,
> independently it's made through a custom action or through
> "container().remove()".
> That way, I can be sure the business logic is going to be executed ALWAYS
> despite how the other developers implement this.
>
> We can re-implement all this event logic for assuring that we always
> delete this kind of domain objects through that action, but I thought
> previous solution would work better, as it's directly attached to the
> object's lifecycle.
>
> In previous threads we talked about the option of being notified of
> framework's events.
>
> Perhaps implementing a @DomainObjectInteraction annotation in a similar
> way to @ActionInteraction could have sense.
>
> What do you think?
>
> Thanks,
>
> Oscar
>
>
>
>
>
>
>
>
> El 12/1/2015, a las 20:38, Jeroen van der Wal <[email protected]>
> escribió:
>
>
> Here's a sample of invalidating the removal of a Party in case it plays
> role in an agreement:
>
> https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/agreement/AgreementRoles.java#L143
>
> HTH
>
> On 12 January 2015 at 19:38, Dan Haywood <[email protected]>
> wrote:
>
> Hi Oscar,
>
> I think we can support this use case, but admittedly it isn't - yet - well
> documented.
>
> First thing to say is that the "removing" lifecycle code hook method that
> you quote isn't actually part of your stacktrace.  As it happens, that's
> probably a good thing...  support for them is a little bit patchy (there
> might be bugs).
>
> So, when I look at your stack trace, what's actually happening is that:
> * BusinessEntity.deleteFromAssignedToBusinessProcesses(...) is performing a
> "removeElement" on a wrapped collection, which fires an event via:
> * CollectionRemoveFromFacetForInteractionAbstract, which is handled by
> * RelationshipsBCMInformationEventHandler.on
>
> So, what you should do in the handler is to look at the event's "phase".
> In fact, you really must pay attention to the phase because it is called
> multiple times:
>
> switch(ev,getPhase()) {
>    case HIDE:
>       ...
>    case DISABLE:
>       ...
>    case VALIDATE:
>       ...
>    case EXECUTING:
>       ...
>    case EXECUTED:
>       ...
> }
>
> As you have probably guessed, your code wants to go into the "EXECUTING"
> bit, which is the pre-execute callback.  I imagine at the moment it is
> firing for all the cases, including the EXECUTED bit, and that's most
> likely why JDO then complains at you when you try to access that deleted
> object.
>
> Hope that makes sense / works... if not, then we can go round the loop.
>
> Cheers
> Dan
>
>
>
>
>
>
>
> Two things about
> Rather than do this on the removing() callback, I suggest you emit an event
> on the action that The event that
>
> On 12 January 2015 at 18:24, GESCONSULTOR - Óscar Bou <
> [email protected]> wrote:
>
> Hi all.
>
> I want to get notified when a domain object is going to be removed.
>
> I have defined it as this:
>
> public class Relationship {
>
>   …
>
>    public void removing() {
>        this.eventBusService.post(new RelationshipRemovingEvent(this));
>    }
>  ...
>
> }
>
> And an Event Handler like this:
>
> public class RelationshipsBCMInformationEventHandler extends
> AbstractXMSService {
>
>    // {{ RELATIONSHIPS EVENTS HANDLER
>
>    @Subscribe
>    @Programmatic
>    public void on(final RelationshipRemovingEvent event) {
>        try {
>            final RelationshipBCMInformation relationshipBCMInformation =
>
>
> this.wrap(this.relationshipsBCMInformation).businessContinuityInformation(event.getRelationship());
>
>            this.getContainer().remove(relationshipBCMInformation);
>            this.getContainer().flush();
>        } catch (final Exception e) {
>            e.printStackTrace();
>            throw new ApplicationException(e);
>        }
>    }
>
>    // }}
>
>    // {{ injected: RelationshipsBCMInformation
>    @Inject
>    private RelationshipsBCMInformation relationshipsBCMInformation;
>
>    // }}
>
>    // {{ injected: EventBusService
>    @Programmatic
>    @PostConstruct
>    public void postConstruct() {
>        this.eventBusService.register(this);
>    }
>
>    @Programmatic
>    @PreDestroy
>    public void preDestroy() {
>        this.eventBusService.unregister(this);
>    }
>
>    @javax.inject.Inject
>    private EventBusService eventBusService;
>    // }}
>
> }
>
>
>
> Problem is that when the code enters the “on” event handler, the
>
> reference
>
> to the relationship accessed on "event.getRelationship()” is already
>
> marked
>
> as deleted:
>
>
> javax.jdo.JDOUserException: No es posible leer campos de un objeto
>
> borrado
>
>
> FailedObject:0[OID]com.xms.framework.architecture.domain.model.Relationship
>
>        at
>
>
> org.datanucleus.api.jdo.state.PersistentNewDeleted.transitionReadField(PersistentNewDeleted.java:106)
>
>        at
>
>
> org.datanucleus.state.AbstractStateManager.transitionReadField(AbstractStateManager.java:650)
>
>        at
> org.datanucleus.state.JDOStateManager.isLoaded(JDOStateManager.java:3194)
>        at
>
>
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.getId(AbstractXMSDomainObject.java)
>
>        at
>
>
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.hashCode(AbstractXMSDomainObject.java:431)
>
>        at java.util.Objects.hashCode(Objects.java:96)
>        at java.util.HashMap$Entry.hashCode(HashMap.java:847)
>        at java.util.AbstractMap.hashCode(AbstractMap.java:494)
>        at
>
>
> org.datanucleus.query.QueryUtils.getKeyForQueryResultsCache(QueryUtils.java:1306)
>
>        at
>
>
> org.datanucleus.store.query.QueryManager.getDatastoreQueryResult(QueryManager.java:470)
>
>        at
>
>
> org.datanucleus.store.rdbms.query.JDOQLQuery.performExecute(JDOQLQuery.java:605)
>
>        at
>
> org.datanucleus.store.query.Query.executeQuery(Query.java:1786)
>
>        at
> org.datanucleus.store.query.Query.executeWithMap(Query.java:1690)
>        at
> org.datanucleus.api.jdo.JDOQuery.executeWithMap(JDOQuery.java:334)
>        at
>
>
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObjectRepositoryAndFactory.doFindByPropMultiTenant(AbstractXMSDomainObjectRepositoryAndFactory.java:759)
>
>        at
>
>
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObjectRepositoryAndFactory.findByPropMultiTenant(AbstractXMSDomainObjectRepositoryAndFactory.java:776)
>
>        at
>
>
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObjectRepositoryAndFactory.findByProp(AbstractXMSDomainObjectRepositoryAndFactory.java:769)
>
>        at
>
>
> com.xms.framework.api.domain.model.isis.AbstractSingletonMultiTenantObjectRepositoryAndFactory.singletonInstance(AbstractSingletonMultiTenantObjectRepositoryAndFactory.java:16)
>
>        at
>
>
> com.xms.framework.risk.domain.model.continuity.RelationshipsBCMInformation.businessContinuityInformation(RelationshipsBCMInformation.java:47)
>
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
>
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>
>        at
>
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>
>        at java.lang.reflect.Method.invoke(Method.java:606)
>        at
>
>
> org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314)
>
>        at
>
>
> org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1)
>
>        at
>
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
>
>        at
>
>
> org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229)
>
>        at
>
>
> org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52)
>
>        at
>
>
> com.xms.framework.risk.domain.model.continuity.RelationshipsBCMInformation_$$_jvstb07_2b.businessContinuityInformation(RelationshipsBCMInformation_$$_jvstb07_2b.java)
>
>        at
>
>
> com.xms.framework.risk.domain.model.continuity.RelationshipsBCMInformationEventHandler.on(RelationshipsBCMInformationEventHandler.java:23)
>
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
>
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>
>        at
>
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>
>        at java.lang.reflect.Method.invoke(Method.java:606)
>        at
>
>
> com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74)
>
>        at
>
>
> com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47)
>
>        at
>
> com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
>
>        at
>
> com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304)
>
>        at com.google.common.eventbus.EventBus.post(EventBus.java:275)
>        at
>
>
> org.apache.isis.applib.services.eventbus.EventBusService.post(EventBusService.java:202)
>
>        at
>
>
> org.apache.isis.core.metamodel.facets.InteractionHelper.postEventForCollection(InteractionHelper.java:202)
>
>        at
>
>
> org.apache.isis.core.metamodel.facets.collections.interaction.CollectionRemoveFromFacetForInteractionAbstract.remove(CollectionRemoveFromFacetForInteractionAbstract.java:103)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.CollectionRemoveFromFacetWrapTransaction$1.execute(CollectionRemoveFromFacetWrapTransaction.java:55)
>
>        at
>
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:160)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.CollectionRemoveFromFacetWrapTransaction.remove(CollectionRemoveFromFacetWrapTransaction.java:52)
>
>        at
>
>
> org.apache.isis.core.metamodel.specloader.specimpl.OneToManyAssociationImpl.removeElement(OneToManyAssociationImpl.java:190)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleCollectionRemoveFromMethod(DomainObjectInvocationHandler.java:526)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:218)
>
>        at
>
>
> org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52)
>
>        at
>
>
> com.xms.framework.architecture.domain.model.business.extensions.businessactor.Person_$$_jvstb07_28.removeFromAssignedToBusinessProcesses(Person_$$_jvstb07_28.java)
>
>        at
>
>
> com.xms.framework.architecture.domain.model.business.BusinessEntity.deleteFromAssignedToBusinessProcesses(BusinessEntity.java:93)
>
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
>
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>
>        at
>
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>
>        at java.lang.reflect.Method.invoke(Method.java:606)
>        at
>
>
> org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314)
>
>        at
>
>
> org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1)
>
>        at
>
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
>
>        at
>
>
> org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229)
>
>        at
>
>
> org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52)
>
>        at
>
>
> com.xms.framework.architecture.domain.model.business.extensions.businessactor.Person_$$_jvstb07_28.deleteFromAssignedToBusinessProcesses(Person_$$_jvstb07_28.java)
>
>        at
>
>
> com.xms.framework.architecture.domain.model.business.BusinessProcess.deleteFromRequiredBusinessEntities(BusinessProcess.java:476)
>
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
>
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>
>        at
>
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>
>        at java.lang.reflect.Method.invoke(Method.java:606)
>        at
>
>
> org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314)
>
>        at
>
>
> org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1)
>
>        at
>
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205)
>
>        at
>
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
>
>        at
>
>
> org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563)
>
>        at
>
>
> org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229)
>
>        at
>
>
> org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52)
>
>        at
>
>
> com.xms.framework.architecture.domain.model.business.BusinessProcess_$$_jvstb07_27.deleteFromRequiredBusinessEntities(BusinessProcess_$$_jvstb07_27.java)
>
>        at
>
>
> com.xms.framework.risk.integration.tests.continuity.RelationshipsBCMInformationTests.testDeleteColletionWithRelationshipAlsoDeletesRelationshipBCMInformation(RelationshipsBCMInformationTests.java:72)
>
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
>
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
>
>        at
>
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>
>        at java.lang.reflect.Method.invoke(Method.java:606)
>        at
>
>
> org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
>
>        at
>
>
> org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
>
>        at
>
>
> org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
>
>        at
>
>
> org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
>
>        at
>
>
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>
>        at
>
>
> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:199)
>
>        at
>
>
> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:146)
>
>        at
>
>
> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>
>        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>        at
>
>
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>
>        at
>
>
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>
>        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>        at
>
> org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>
>        at
> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>        at
>
> org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>
>        at
>
> org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>
>        at
>
>
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>
>        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>        at
>
>
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>
>        at
>
>
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>
>        at
>
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>
>        at
>
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>
>        at
>
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>
>        at
>
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
>
>
>
> So, as it could be a quite “common” events-related use case (referencing
> the same entity “before” deleting it), could the event be dispatched
>
> BEFORE
>
> sending the object to DN to mark it as deleted?
>
> Or, is there any other way to detect when an object is going to be
>
> deleted
>
> (previously to being deleted, obviously) ?
>
>
> Thanks in advance,
>
> Oscar
>
>
>
>
>
>
>
> Óscar Bou Bou
> Responsable de Producto
> Auditor Jefe de Certificación ISO 27001 en BSI
> CISA, CRISC, APMG ISO 20000, ITIL-F
>
>    902 900 231 / 620 267 520
>    http://www.twitter.com/oscarbou
>
>    http://es.linkedin.com/in/oscarbou
>
>    http://www.GesConsultor.com <http://www.gesconsultor.com/>
>
>
>
> Este mensaje y los ficheros anexos son confidenciales. Los mismos
> contienen información reservada que no puede ser difundida. Si usted ha
> recibido este correo por error, tenga la amabilidad de eliminarlo de su
> sistema y avisar al remitente mediante reenvío a su dirección electrónica;
> no deberá copiar el mensaje ni divulgar su contenido a ninguna persona.
> Su dirección de correo electrónico junto a sus datos personales constan en
> un fichero titularidad de Gesdatos Software, S.L. cuya finalidad es la de
> mantener el contacto con Ud. Si quiere saber de qué información disponemos
> de Ud., modificarla, y en su caso, cancelarla, puede hacerlo enviando un
> escrito al efecto, acompañado de una fotocopia de su D.N.I. a la siguiente
> dirección: Gesdatos Software, S.L. , Paseo de la Castellana, 153 bajo -
> 28046 (Madrid), y Avda. Cortes Valencianas num. 50, 1ºC - 46015 (Valencia).
> Asimismo, es su responsabilidad comprobar que este mensaje o sus archivos
> adjuntos no contengan virus informáticos, y en caso que los tuvieran
> eliminarlos.
>
>
>
>
>
>

Reply via email to