001/*
002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $
020 */
021
022package org.nuxeo.ecm.platform.types;
023
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.HashMap;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031
032import org.nuxeo.ecm.core.schema.DocumentTypeDescriptor;
033import org.nuxeo.ecm.core.schema.SchemaManager;
034import org.nuxeo.ecm.core.schema.SchemaManagerImpl;
035import org.nuxeo.runtime.api.Framework;
036import org.nuxeo.runtime.model.ContributionFragmentRegistry;
037
038public class TypeRegistry extends ContributionFragmentRegistry<Type> {
039
040    protected Map<String, Type> types = new HashMap<String, Type>();
041
042    protected Map<String, DocumentTypeDescriptor> dtds = new HashMap<>();
043
044    @Override
045    public String getContributionId(Type contrib) {
046        return contrib.getId();
047    }
048
049    @Override
050    public void contributionUpdated(String id, Type contrib, Type newOrigContrib) {
051        if (contrib.getRemove()) {
052            types.remove(id);
053            removeCoreContribution(id);
054        } else {
055            types.put(id, contrib);
056            updateCoreContribution(id, contrib);
057        }
058    }
059
060    @Override
061    public void contributionRemoved(String id, Type origContrib) {
062        types.remove(id);
063        removeCoreContribution(id);
064    }
065
066    @Override
067    public Type clone(Type orig) {
068        if (orig != null) {
069            return orig.clone();
070        }
071        return null;
072    }
073
074    @Override
075    public void merge(Type newType, Type oldType) {
076        boolean remove = newType.getRemove();
077        // keep old remove info: if old type was removed, new type should
078        // replace the old one completely
079        boolean wasRemoved = oldType.getRemove();
080        oldType.setRemove(remove);
081        if (remove) {
082            // don't bother merging
083            return;
084        }
085
086        String icon = newType.getIcon();
087        if (icon != null || wasRemoved) {
088            oldType.setIcon(icon);
089        }
090        String iconExpanded = newType.getIconExpanded();
091        if (iconExpanded != null || wasRemoved) {
092            oldType.setIconExpanded(iconExpanded);
093        }
094        String bigIcon = newType.getBigIcon();
095        if (bigIcon != null || wasRemoved) {
096            oldType.setBigIcon(bigIcon);
097        }
098        String bigIconExpanded = newType.getBigIconExpanded();
099        if (bigIconExpanded != null || wasRemoved) {
100            oldType.setBigIconExpanded(bigIconExpanded);
101        }
102        String label = newType.getLabel();
103        if (label != null || wasRemoved) {
104            oldType.setLabel(label);
105        }
106        String description = newType.getDescription();
107        if (description != null || wasRemoved) {
108            oldType.setDescription(description);
109        }
110        String category = newType.getCategory();
111        if (category != null || wasRemoved) {
112            oldType.setCategory(category);
113        }
114
115        Map<String, SubType> newTypeAllowedSubTypes = newType.getAllowedSubTypes();
116        if (wasRemoved) {
117            oldType.setAllowedSubTypes(newTypeAllowedSubTypes);
118        } else {
119            if (newTypeAllowedSubTypes != null) {
120                Set<String> newTypeKeySet = newTypeAllowedSubTypes.keySet();
121                Map<String, SubType> oldTypeAllowedSubTypes = oldType.getAllowedSubTypes();
122                for (String newTypeKey : newTypeKeySet) {
123                    oldTypeAllowedSubTypes.put(newTypeKey, newTypeAllowedSubTypes.get(newTypeKey));
124                }
125
126            }
127
128            // Code added to delete the denied SubType from allowed subtypes
129
130            List<String> result = new ArrayList<String>();
131            String[] deniedSubTypes = newType.getDeniedSubTypes();
132            Map<String, SubType> oldTypeAllowedSubTypes = oldType.getAllowedSubTypes();
133            boolean toAdd = true;
134
135            if (oldTypeAllowedSubTypes != null) {
136                Set<String> oldTypeKeySet = oldTypeAllowedSubTypes.keySet();
137                for (String allowedSubType : oldTypeKeySet) {
138                    for (String deniedSubType : deniedSubTypes) {
139                        if (deniedSubType.equals(allowedSubType)) {
140                            toAdd = false;
141                            break;
142                        }
143                    }
144                    if (toAdd) {
145                        result.add(allowedSubType);
146                    }
147                    toAdd = true;
148                }
149            }
150
151            Map<String, SubType> mapResult = new HashMap<String, SubType>();
152            for (String resultTypeName : result) {
153                mapResult.put(resultTypeName, oldTypeAllowedSubTypes.get(resultTypeName));
154            }
155
156            oldType.setAllowedSubTypes(mapResult);
157
158            // end of added code
159        }
160
161        String defaultView = newType.getDefaultView();
162        if (defaultView != null || wasRemoved) {
163            oldType.setDefaultView(defaultView);
164        }
165        String createView = newType.getCreateView();
166        if (createView != null || wasRemoved) {
167            oldType.setCreateView(createView);
168        }
169        String editView = newType.getEditView();
170        if (editView != null || wasRemoved) {
171            oldType.setEditView(editView);
172        }
173
174        for (TypeView view : newType.getViews()) {
175            oldType.setView(view);
176        }
177
178        Map<String, Layouts> layouts = newType.getLayouts();
179        if (wasRemoved) {
180            oldType.setLayouts(layouts);
181        } else {
182            if (layouts != null) {
183                Map<String, Layouts> layoutsMerged = new HashMap<String, Layouts>(oldType.getLayouts());
184                for (Map.Entry<String, Layouts> entry : layouts.entrySet()) {
185                    String key = entry.getKey();
186                    Layouts newLayouts = entry.getValue();
187                    if (layoutsMerged.containsKey(key) && newLayouts.getAppend()) {
188                        List<String> allLayouts = new ArrayList<String>();
189                        for (String layoutName : layoutsMerged.get(key).getLayouts()) {
190                            allLayouts.add(layoutName);
191                        }
192                        for (String layoutName : newLayouts.getLayouts()) {
193                            allLayouts.add(layoutName);
194                        }
195                        Layouts mergedLayouts = new Layouts();
196                        mergedLayouts.layouts = allLayouts.toArray(new String[allLayouts.size()]);
197                        layoutsMerged.put(key, mergedLayouts);
198                    } else {
199                        layoutsMerged.put(key, newLayouts);
200                    }
201                }
202                oldType.setLayouts(layoutsMerged);
203            }
204        }
205
206        Map<String, DocumentContentViews> contentViews = newType.getContentViews();
207        if (wasRemoved) {
208            oldType.setContentViews(contentViews);
209        } else {
210            if (contentViews != null) {
211                Map<String, DocumentContentViews> cvMerged = new HashMap<String, DocumentContentViews>(
212                        oldType.getContentViews());
213                for (Map.Entry<String, DocumentContentViews> entry : contentViews.entrySet()) {
214                    String key = entry.getKey();
215                    DocumentContentViews newContentViews = entry.getValue();
216                    if (cvMerged.containsKey(key) && newContentViews.getAppend()) {
217                        List<DocumentContentView> allContentViews = new ArrayList<DocumentContentView>();
218                        for (DocumentContentView cv : cvMerged.get(key).getContentViews()) {
219                            allContentViews.add(cv);
220                        }
221                        for (DocumentContentView cv : newContentViews.getContentViews()) {
222                            allContentViews.add(cv);
223                        }
224                        DocumentContentViews mergedContentViews = new DocumentContentViews();
225                        mergedContentViews.contentViews = allContentViews.toArray(new DocumentContentView[allContentViews.size()]);
226                        cvMerged.put(key, mergedContentViews);
227                    } else {
228                        cvMerged.put(key, newContentViews);
229                    }
230                }
231                oldType.setContentViews(cvMerged);
232            }
233        }
234    }
235
236    public boolean hasType(String id) {
237        return types.containsKey(id);
238    }
239
240    public Collection<Type> getTypes() {
241        return Collections.unmodifiableCollection(types.values());
242    }
243
244    public Type getType(String id) {
245        return types.get(id);
246    }
247
248    /**
249     * @since 8.10
250     */
251    protected void recomputeTypes() {
252        for (Type type : types.values()) {
253            type.setAllowedSubTypes(getCoreAllowedSubtypes(type));
254            //  do not need to add denied subtypes because allowed subtypes already come filtered from core
255            type.setDeniedSubTypes(new String[0]);
256        }
257    }
258
259    /**
260     * @since 8.10
261     */
262    protected Map<String, SubType> getCoreAllowedSubtypes(Type type) {
263        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
264        Collection<String> coreAllowedSubtypes = schemaManager.getAllowedSubTypes(type.getId());
265        if (coreAllowedSubtypes == null) {
266            // there are no subtypes to take care of
267            return Collections.emptyMap();
268        }
269
270        Map<String, SubType> ecmSubTypes = type.getAllowedSubTypes();
271        Map<String, SubType> allowedSubTypes = new HashMap<>();
272        SubType subtype;
273        for (String name : coreAllowedSubtypes) {
274            if (ecmSubTypes.containsKey(name)) {
275                subtype = ecmSubTypes.get(name);
276            } else {
277                subtype = new SubType();
278                subtype.setName(name);
279            }
280            allowedSubTypes.put(name, subtype);
281        }
282
283        return allowedSubTypes;
284    }
285
286    /**
287     * @since 8.4
288     */
289    protected void updateCoreContribution(String id, Type contrib) {
290        SchemaManagerImpl schemaManager = (SchemaManagerImpl) Framework.getService(SchemaManager.class);
291
292        // if there's already a core contribution, unregiser it and register a new one
293        if (dtds.containsKey(id)) {
294            schemaManager.unregisterDocumentType(dtds.get(id));
295            dtds.remove(id);
296        }
297
298        DocumentTypeDescriptor dtd = new DocumentTypeDescriptor();
299        dtd.name = contrib.getId();
300        dtd.subtypes = contrib.getAllowedSubTypes().keySet().toArray(new String[contrib.getAllowedSubTypes().size()]);
301        dtd.forbiddenSubtypes = contrib.getDeniedSubTypes();
302        dtd.append = true;
303
304        // only make a core contrib if there are changes on subtypes
305        if (dtd.subtypes.length > 0 || dtd.forbiddenSubtypes.length > 0) {
306            dtds.put(id, dtd);
307            schemaManager.registerDocumentType(dtd);
308        }
309    }
310
311    /**
312     * @since 8.4
313     */
314    protected void removeCoreContribution(String id) {
315        if (dtds.containsKey(id)) {
316            SchemaManagerImpl schemaManager = (SchemaManagerImpl) Framework.getService(SchemaManager.class);
317            schemaManager.unregisterDocumentType(dtds.get(id));
318            dtds.remove(id);
319        }
320    }
321
322}