001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 */
019
020package org.apache.isis.core.progmodel.facets.collections.event;
021
022import java.lang.reflect.Field;
023import java.lang.reflect.InvocationTargetException;
024import java.util.Collection;
025import java.util.List;
026
027import com.google.common.collect.Lists;
028
029import org.apache.isis.applib.FatalException;
030import org.apache.isis.applib.Identifier;
031import org.apache.isis.applib.services.eventbus.CollectionRemovedFromEvent;
032import org.apache.isis.applib.services.eventbus.EventBusService;
033import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
034import org.apache.isis.core.metamodel.adapter.ServicesProvider;
035import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
036import org.apache.isis.core.metamodel.facetapi.Facet;
037import org.apache.isis.core.metamodel.facetapi.FacetHolder;
038import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
039import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionRemovedFromEventFacet;
040import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionRemovedFromEventFacetAbstract;
041import org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet;
042import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
043
044public class PostsCollectionRemovedFromEventFacetAnnotation extends
045                PostsCollectionRemovedFromEventFacetAbstract {
046
047        private final PropertyOrCollectionAccessorFacet getterFacet;
048        private final CollectionRemoveFromFacet collectionRemoveFromFacet;
049    private final ServicesInjector servicesInjector;
050
051        private EventBusService eventBusService;
052        private boolean searchedForEventBusService = false;
053
054        public PostsCollectionRemovedFromEventFacetAnnotation(
055                        final Class<? extends CollectionRemovedFromEvent<?, ?>> eventType,
056                        final PropertyOrCollectionAccessorFacet getterFacet,
057                        final CollectionRemoveFromFacet collectionRemoveFromFacet,
058            final ServicesInjector servicesInjector,
059                        final FacetHolder holder) {
060                super(eventType, holder);
061                this.getterFacet = getterFacet;
062                this.collectionRemoveFromFacet = collectionRemoveFromFacet;
063        this.servicesInjector = servicesInjector;
064        }
065
066        @Override
067        public void remove(ObjectAdapter targetAdapter,
068                        ObjectAdapter referencedObjectAdapter) {
069                if (this.collectionRemoveFromFacet == null) {
070                        return;
071                }
072                eventBusService = getEventBusService();
073                if (eventBusService == null) {
074                        collectionRemoveFromFacet.remove(targetAdapter,
075                                        referencedObjectAdapter);
076                        return;
077                }
078
079                final Object referencedObject = AdapterUtils
080                                .unwrap(referencedObjectAdapter);
081
082                // get hold of underlying collection
083                final Object collection = getterFacet.getProperty(targetAdapter);
084
085                // don't post event if the collections does not contain object
086                if (!((Collection<?>) collection).contains(referencedObject)) {
087                        return;
088                }
089
090                // contains the element. So the event must be posted.
091                collectionRemoveFromFacet
092                                .remove(targetAdapter, referencedObjectAdapter);
093
094                postEvent(targetAdapter, getIdentified().getIdentifier(),
095                                referencedObject);
096        }
097
098        @SuppressWarnings({ "rawtypes", "unchecked" })
099        private void postEvent(final ObjectAdapter targetAdapter,
100                        final Identifier identifier, final Object removedReference) {
101
102                try {
103                        final Class type = value();
104                        final Object source = AdapterUtils.unwrap(targetAdapter);
105                        final CollectionRemovedFromEvent<?, ?> event = Util.newEvent(type, source, identifier, removedReference);
106                        eventBusService.post(event);
107                } catch (Exception e) {
108                        throw new FatalException(e);
109                }
110        }
111
112    private EventBusService getEventBusService() {
113        if (!searchedForEventBusService) {
114            eventBusService = this.servicesInjector.lookupService(EventBusService.class);
115        }
116        searchedForEventBusService = true;
117        return eventBusService;
118    }
119
120        // //////////////////////////////////////
121        // MultiTypedFacet
122        // //////////////////////////////////////
123
124        @SuppressWarnings("unchecked")
125        @Override
126        public Class<? extends Facet>[] facetTypes() {
127                return Lists.newArrayList(type(), // ie CollectionRemoveFromFacet
128                                PostsCollectionRemovedFromEventFacet.class).toArray(new Class[] {});
129        }
130
131        @SuppressWarnings("unchecked")
132        @Override
133        public <T extends Facet> T getFacet(Class<T> facet) {
134                return (T) this;
135        }
136
137}