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.util.Set;
023
024import com.google.common.collect.Lists;
025
026import org.apache.isis.applib.FatalException;
027import org.apache.isis.applib.Identifier;
028import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
029import org.apache.isis.applib.services.eventbus.EventBusService;
030import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
031import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
032import org.apache.isis.core.metamodel.facetapi.Facet;
033import org.apache.isis.core.metamodel.facetapi.FacetHolder;
034import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
035import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionAddedToEventFacet;
036import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionAddedToEventFacetAbstract;
037import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
038import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
039
040public class PostsCollectionAddedToEventFacetAnnotation 
041        extends PostsCollectionAddedToEventFacetAbstract {
042
043    private final PropertyOrCollectionAccessorFacet getterFacet;
044        private final CollectionAddToFacet collectionAddToFacet;
045        private final ServicesInjector servicesInjector;
046
047        private EventBusService eventBusService;
048        private boolean searchedForEventBusService = false;
049
050        public PostsCollectionAddedToEventFacetAnnotation(
051                        final Class<? extends CollectionAddedToEvent<?, ?>> eventType,
052                        final PropertyOrCollectionAccessorFacet getterFacet,
053                        final CollectionAddToFacet collectionAddToFacet,
054                    final ServicesInjector servicesInjector,
055                        final FacetHolder holder) {
056                super(eventType, holder);
057        this.getterFacet = getterFacet;
058                this.collectionAddToFacet = collectionAddToFacet;
059                this.servicesInjector = servicesInjector;
060        }
061
062        @Override
063        public void add(ObjectAdapter targetAdapter, ObjectAdapter referencedObjectAdapter) {
064                if (this.collectionAddToFacet == null) {
065                        return;
066                }
067                eventBusService = getEventBusService();
068                if (eventBusService == null) {
069                        collectionAddToFacet.add(targetAdapter, referencedObjectAdapter);
070                        return;
071                }
072
073                final Object referencedObject = AdapterUtils.unwrap(referencedObjectAdapter);
074                
075                // get hold of underlying collection
076                final Object collection = getterFacet.getProperty(targetAdapter);
077
078                // don't post event if has set semantics and contains object
079                if(collection instanceof Set) {
080            Set<?> set = (Set<?>) collection;
081            if(set.contains(referencedObject)) {
082                return;
083            }
084                }
085
086                // either doesn't contain object, or doesn't have set semantics, so post event
087                collectionAddToFacet.add(targetAdapter, referencedObjectAdapter);
088                
089                postEvent(targetAdapter, getIdentified().getIdentifier(), referencedObject);
090        }
091
092        @SuppressWarnings({ "rawtypes", "unchecked" })
093        private void postEvent(
094                final ObjectAdapter targetAdapter,
095            final Identifier identifier,
096                        final Object addedReference) {
097            
098                try {
099                        final Class type = value();
100            final Object source = AdapterUtils.unwrap(targetAdapter);
101                        final CollectionAddedToEvent<?, ?> event = Util.newEvent(type, source, identifier, addedReference);
102                        eventBusService.post(event);
103                } catch (Exception e) {
104                        throw new FatalException(e);
105                }
106        }
107
108    private EventBusService getEventBusService() {
109        if (!searchedForEventBusService) {
110            eventBusService = this.servicesInjector.lookupService(EventBusService.class);
111        }
112        searchedForEventBusService = true;
113        return eventBusService;
114    }
115
116        // //////////////////////////////////////
117        // MultiTypedFacet
118        // //////////////////////////////////////
119
120        @SuppressWarnings("unchecked")
121        @Override
122        public Class<? extends Facet>[] facetTypes() {
123                return Lists.newArrayList(
124                            type(), // ie CollectionAddedToFacet
125                        PostsCollectionAddedToEventFacet.class
126                                ).toArray(
127                                new Class[] {});
128        }
129
130        @SuppressWarnings("unchecked")
131        @Override
132        public <T extends Facet> T getFacet(Class<T> facet) {
133                return (T) this;
134        }
135
136}