001/*
002 *  Copyright 2018 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.cms.contenttype;
017
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.avalon.framework.service.ServiceException;
022import org.apache.cocoon.ProcessingException;
023
024import org.ametys.cms.model.restrictions.ContentRestrictedModelItemHelper;
025import org.ametys.cms.model.restrictions.RestrictedModelItem;
026import org.ametys.cms.model.restrictions.Restrictions;
027import org.ametys.cms.repository.Content;
028import org.ametys.plugins.repository.data.external.ExternalizableDataProviderExtensionPoint;
029import org.ametys.runtime.i18n.I18nizableText;
030import org.ametys.runtime.model.DefinitionContext;
031import org.ametys.runtime.model.ElementDefinition;
032import org.ametys.runtime.model.ModelItem;
033
034/**
035 * The definition of a content type attribute
036 * @param <T> Type of the attribute value
037 */
038public class AttributeDefinition<T> extends ElementDefinition<T> implements RestrictedModelItem<Content>
039{
040    private ContentRestrictedModelItemHelper _restrictedModelItemHelper;
041    private ExternalizableDataProviderExtensionPoint _externalizableDataProviderExtensionPoint;
042
043    private Restrictions _restrictions;
044    
045    /**
046     * Set the restrictions for the attribute
047     * @param restrictions the restrictions to set
048     */
049    public void setRestrictions(Restrictions restrictions)
050    {
051        _restrictions = restrictions;
052    }
053
054    public boolean canRead(Content content)
055    {
056        ContentRestrictedModelItemHelper restrictedModelItemHelper = _getRestrictedModelItemHelper();
057        ContentType contentType = (ContentType) getModel();
058        return restrictedModelItemHelper.canRead(content, this, _restrictions) && contentType.canRead(content, this);
059    }
060
061    public boolean canWrite(Content content)
062    {
063        ContentRestrictedModelItemHelper restrictedModelItemHelper = _getRestrictedModelItemHelper();
064        ContentType contentType = (ContentType) getModel();
065        return restrictedModelItemHelper.canWrite(content, this, _restrictions) && contentType.canWrite(content, this);
066    }
067    
068    /**
069     * Retrieves the helper for {@link ModelItem}s with restrictions on contents 
070     * @return the {@link ContentRestrictedModelItemHelper}
071     */
072    protected ContentRestrictedModelItemHelper _getRestrictedModelItemHelper()
073    {
074        if (_restrictedModelItemHelper == null)
075        {
076            try
077            {
078                _restrictedModelItemHelper = (ContentRestrictedModelItemHelper) __serviceManager.lookup(ContentRestrictedModelItemHelper.ROLE);
079            }
080            catch (ServiceException e)
081            {
082                throw new RuntimeException("Unable to lookup after the restricted model item helper component", e);
083            }
084        }
085        
086        return _restrictedModelItemHelper;
087    }
088    
089    @SuppressWarnings("unchecked")
090    @Override
091    protected Map<String, Object> _toJSON(DefinitionContext context) throws ProcessingException
092    {
093        Map<String, Object> result = super._toJSON(context);
094        
095        Content content = context.getObject()
096                .filter(Content.class::isInstance)
097                .map(Content.class::cast)
098                .orElse(null);
099        
100        if (content != null)
101        {
102            if (context.isEdition() && _getExternalizableDataProviderExtensionPoint().isDataExternalizable(content, this))
103            {
104                // Wrap the widget
105                result.put("widget", "edition.externalizable");
106
107                if (getWidget() != null)
108                {
109                    Map<String, I18nizableText> widgetParameters = new HashMap<>();
110                    if (result.containsKey("widget-params"))
111                    {
112                        widgetParameters = (Map<String, I18nizableText>) result.get("widget-params");
113                    }
114
115                    widgetParameters.put("wrapped-widget", new I18nizableText(getWidget()));
116
117                    if (!widgetParameters.isEmpty())
118                    {
119                        result.put("widget-params", widgetParameters);
120                    }
121                }
122            }
123        }
124        
125        if (!canWrite(content))
126        {
127            result.put("can-not-write", true);
128        }
129        
130        return result;
131    }
132    
133    @Override
134    protected boolean _shouldJSONBeEmpty(DefinitionContext context)
135    {
136        return context.getObject()
137                .filter(Content.class::isInstance)
138                .map(Content.class::cast)
139                .map(content -> !canRead(content))
140                .orElse(false);
141    }
142    
143    /**
144     * Retrieves the {@link ExternalizableDataProviderExtensionPoint} 
145     * @return the {@link ExternalizableDataProviderExtensionPoint}
146     */
147    protected ExternalizableDataProviderExtensionPoint _getExternalizableDataProviderExtensionPoint()
148    {
149        if (_externalizableDataProviderExtensionPoint == null)
150        {
151            try
152            {
153                _externalizableDataProviderExtensionPoint = (ExternalizableDataProviderExtensionPoint) __serviceManager.lookup(ExternalizableDataProviderExtensionPoint.ROLE);
154            }
155            catch (ServiceException e)
156            {
157                throw new RuntimeException("Unable to lookup after the externalizable data provider extension point", e);
158            }
159        }
160        
161        return _externalizableDataProviderExtensionPoint;
162    }
163}