001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.odfweb.observation;
017
018import java.util.Map;
019
020import org.apache.avalon.framework.service.ServiceException;
021import org.apache.avalon.framework.service.ServiceManager;
022import org.apache.avalon.framework.service.Serviceable;
023import org.apache.commons.lang.StringUtils;
024import org.apache.commons.lang3.ArrayUtils;
025
026import org.ametys.cms.ObservationConstants;
027import org.ametys.cms.content.ContentHelper;
028import org.ametys.cms.contenttype.ContentAttributeDefinition;
029import org.ametys.cms.contenttype.ContentType;
030import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
031import org.ametys.cms.repository.Content;
032import org.ametys.core.observation.Event;
033import org.ametys.core.observation.Observer;
034import org.ametys.odf.ProgramItem;
035import org.ametys.odf.enumeration.OdfReferenceTableHelper;
036import org.ametys.odf.orgunit.OrgUnit;
037import org.ametys.odf.program.ProgramFactory;
038import org.ametys.odf.tree.OdfClassificationHandler;
039import org.ametys.plugins.odfweb.repository.FirstLevelPageFactory;
040import org.ametys.plugins.odfweb.repository.OdfPageHandler;
041import org.ametys.plugins.repository.AmetysObjectIterable;
042import org.ametys.plugins.repository.AmetysObjectResolver;
043import org.ametys.plugins.repository.query.expression.Expression;
044import org.ametys.plugins.repository.query.expression.VirtualFactoryExpression;
045import org.ametys.runtime.model.ModelItem;
046import org.ametys.runtime.plugin.component.AbstractLogEnabled;
047import org.ametys.web.repository.page.Page;
048import org.ametys.web.repository.page.PageQueryHelper;
049
050/**
051 * This observer clears the cache of enumerated {@link OrgUnit} values or {@link Content}s which are {@link ContentHelper#isReferenceTable(Content) part of reference table} 
052 * when an {@link OrgUnit} or reference table content is added, modified, moved or deleted.
053 */
054public class ClearLevelCacheObserver extends AbstractLogEnabled implements Observer, Serviceable
055{
056    private ContentHelper _contentHelper;
057    private OdfClassificationHandler _odfClassificationHandler;
058    private AmetysObjectResolver _resolver;
059    private OdfPageHandler _odfPageHandler;
060    private ContentTypeExtensionPoint _cTypeEP;
061    private OdfReferenceTableHelper _odfReferenceTableHelper;
062    
063    @Override
064    public void service(ServiceManager manager) throws ServiceException
065    {
066        _contentHelper = (ContentHelper) manager.lookup(ContentHelper.ROLE);
067        _odfClassificationHandler = (OdfClassificationHandler) manager.lookup(OdfClassificationHandler.ROLE);
068        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
069        _odfPageHandler = (OdfPageHandler) manager.lookup(OdfPageHandler.ROLE);
070        _cTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE);
071        _odfReferenceTableHelper = (OdfReferenceTableHelper) manager.lookup(OdfReferenceTableHelper.ROLE);
072    }
073    
074    @Override
075    public boolean supports(Event event)
076    {
077        String eventId = event.getId();
078        Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
079        return (eventId.equals(ObservationConstants.EVENT_CONTENT_DELETING)
080                || eventId.equals(ObservationConstants.EVENT_CONTENT_MODIFIED/* handles moved orgUnit too */) 
081                || eventId.equals(ObservationConstants.EVENT_CONTENT_ADDED))
082                && content != null && (content instanceof OrgUnit || _contentHelper.isReferenceTable(content)); 
083    }
084    
085    @Override
086    public int getPriority(Event event)
087    {
088        return MAX_PRIORITY;
089    }
090
091    @Override
092    public void observe(Event event, Map<String, Object> transientVars) throws Exception
093    {
094        Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
095        if (content instanceof OrgUnit)
096        {
097            _odfClassificationHandler.clearLevelValues(ProgramItem.ORG_UNITS_REFERENCES, content.getLanguage());
098        }
099        else
100        {
101            AmetysObjectIterable<Page> rootPages = _getODFRootPages();
102            if (rootPages.getSize() == 0)
103            {
104                getLogger().debug("There is no ODF root page, nothing to invalidate");
105                return;
106            }
107            
108            if (_odfReferenceTableHelper.isTableReferenceEntry(content))
109            {
110                // The target content is an entry of a reference table
111                for (Page rootPage : rootPages)
112                {
113                    String level1Attribute = _odfPageHandler.getLevel1Metadata(rootPage);
114                    if (_isPartOfClassification(content, level1Attribute))
115                    {
116                        _odfClassificationHandler.clearLevelValues(level1Attribute, null);
117                    }
118                    
119                    String level2Attribute = _odfPageHandler.getLevel2Metadata(rootPage);
120                    if (_isPartOfClassification(content, level2Attribute))
121                    {
122                        _odfClassificationHandler.clearLevelValues(level2Attribute, null);
123                    }
124                }
125                
126            }
127        }
128    }
129    
130    private boolean _isPartOfClassification(Content targetContent, String attributName)
131    {
132        if (StringUtils.isNotEmpty(attributName))
133        {
134            ContentType programCType = _cTypeEP.getExtension(ProgramFactory.PROGRAM_CONTENT_TYPE);
135            
136            if (programCType.hasModelItem(attributName))
137            {
138                ModelItem modelItem = programCType.getModelItem(attributName);
139                
140                if (modelItem instanceof ContentAttributeDefinition)
141                {
142                    return ArrayUtils.contains(targetContent.getTypes(), ((ContentAttributeDefinition) modelItem).getContentTypeId());
143                }
144            }
145        }
146        
147        return false;
148    }
149    
150    /**
151     * Get the ODF root pages
152     * @return the ODF root pages
153     */
154    protected AmetysObjectIterable<Page> _getODFRootPages()
155    {
156        Expression expression = new VirtualFactoryExpression(FirstLevelPageFactory.class.getName());
157        String query = PageQueryHelper.getPageXPathQuery(null, null, null, expression, null);
158        
159        return _resolver.query(query);
160    }
161}