001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.dynamicdatamapping.service.impl;
016    
017    import com.liferay.portal.LocaleException;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.language.LanguageUtil;
021    import com.liferay.portal.kernel.search.Indexer;
022    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
023    import com.liferay.portal.kernel.systemevent.SystemEvent;
024    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
025    import com.liferay.portal.kernel.util.ArrayUtil;
026    import com.liferay.portal.kernel.util.GroupThreadLocal;
027    import com.liferay.portal.kernel.util.OrderByComparator;
028    import com.liferay.portal.kernel.util.SetUtil;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.model.ResourceConstants;
033    import com.liferay.portal.model.SystemEventConstants;
034    import com.liferay.portal.model.User;
035    import com.liferay.portal.security.auth.CompanyThreadLocal;
036    import com.liferay.portal.service.ServiceContext;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.PropsValues;
039    import com.liferay.portlet.dynamicdatamapping.NoSuchStructureException;
040    import com.liferay.portlet.dynamicdatamapping.RequiredStructureException;
041    import com.liferay.portlet.dynamicdatamapping.StructureDefinitionException;
042    import com.liferay.portlet.dynamicdatamapping.StructureDuplicateElementException;
043    import com.liferay.portlet.dynamicdatamapping.StructureDuplicateStructureKeyException;
044    import com.liferay.portlet.dynamicdatamapping.StructureNameException;
045    import com.liferay.portlet.dynamicdatamapping.io.DDMFormXSDDeserializerUtil;
046    import com.liferay.portlet.dynamicdatamapping.io.DDMFormXSDSerializerUtil;
047    import com.liferay.portlet.dynamicdatamapping.model.DDMForm;
048    import com.liferay.portlet.dynamicdatamapping.model.DDMFormField;
049    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
050    import com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants;
051    import com.liferay.portlet.dynamicdatamapping.model.DDMStructureVersion;
052    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
053    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
054    import com.liferay.portlet.dynamicdatamapping.service.base.DDMStructureLocalServiceBaseImpl;
055    import com.liferay.portlet.dynamicdatamapping.util.DDMFormTemplateSynchonizer;
056    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
057    import com.liferay.portlet.journal.model.JournalArticle;
058    import com.liferay.portlet.journal.model.JournalFolderConstants;
059    
060    import java.util.ArrayList;
061    import java.util.Date;
062    import java.util.HashSet;
063    import java.util.List;
064    import java.util.Locale;
065    import java.util.Map;
066    import java.util.Set;
067    import java.util.concurrent.Callable;
068    
069    /**
070     * Provides the local service for accessing, adding, deleting, and updating
071     * dynamic data mapping (DDM) structures.
072     *
073     * <p>
074     * DDM structures (structures) are used in Liferay to store structured content
075     * like document types, dynamic data definitions, or web contents.
076     * </p>
077     *
078     * <p>
079     * Structures support inheritance via parent structures. They also support
080     * multi-language names and descriptions.
081     * </p>
082     *
083     * <p>
084     * Structures can be related to many models in Liferay, such as those for web
085     * contents, dynamic data lists, and documents. This relationship can be
086     * established via the model's class name ID.
087     * </p>
088     *
089     * @author Brian Wing Shun Chan
090     * @author Bruno Basto
091     * @author Marcellus Tavares
092     * @author Juan Fern??ndez
093     */
094    public class DDMStructureLocalServiceImpl
095            extends DDMStructureLocalServiceBaseImpl {
096    
097            @Override
098            public DDMStructure addStructure(
099                            long userId, long groupId, long parentStructureId, long classNameId,
100                            String structureKey, Map<Locale, String> nameMap,
101                            Map<Locale, String> descriptionMap, DDMForm ddmForm,
102                            String storageType, int type, ServiceContext serviceContext)
103                    throws PortalException {
104    
105                    // Structure
106    
107                    User user = userPersistence.findByPrimaryKey(userId);
108    
109                    if (Validator.isNull(structureKey)) {
110                            structureKey = String.valueOf(counterLocalService.increment());
111                    }
112                    else {
113                            structureKey = StringUtil.toUpperCase(structureKey.trim());
114                    }
115    
116                    Date now = new Date();
117    
118                    validate(
119                            groupId, parentStructureId, classNameId, structureKey, nameMap,
120                            ddmForm);
121    
122                    long structureId = counterLocalService.increment();
123    
124                    DDMStructure structure = ddmStructurePersistence.create(structureId);
125    
126                    structure.setUuid(serviceContext.getUuid());
127                    structure.setGroupId(groupId);
128                    structure.setCompanyId(user.getCompanyId());
129                    structure.setUserId(user.getUserId());
130                    structure.setUserName(user.getFullName());
131                    structure.setCreateDate(serviceContext.getCreateDate(now));
132                    structure.setModifiedDate(serviceContext.getModifiedDate(now));
133                    structure.setParentStructureId(parentStructureId);
134                    structure.setClassNameId(classNameId);
135                    structure.setStructureKey(structureKey);
136                    structure.setVersion(DDMStructureConstants.VERSION_DEFAULT);
137                    structure.setNameMap(nameMap);
138                    structure.setDescriptionMap(descriptionMap);
139                    structure.setDefinition(DDMFormXSDSerializerUtil.serialize(ddmForm));
140                    structure.setStorageType(storageType);
141                    structure.setType(type);
142    
143                    ddmStructurePersistence.update(structure);
144    
145                    // Resources
146    
147                    if (serviceContext.isAddGroupPermissions() ||
148                            serviceContext.isAddGuestPermissions()) {
149    
150                            addStructureResources(
151                                    structure, serviceContext.isAddGroupPermissions(),
152                                    serviceContext.isAddGuestPermissions());
153                    }
154                    else {
155                            addStructureResources(
156                                    structure, serviceContext.getGroupPermissions(),
157                                    serviceContext.getGuestPermissions());
158                    }
159    
160                    // Structure version
161    
162                    addStructureVersion(structure, DDMStructureConstants.VERSION_DEFAULT);
163    
164                    return structure;
165            }
166    
167            /**
168             * Adds a structure referencing its parent structure.
169             *
170             * @param      userId the primary key of the structure's creator/owner
171             * @param      groupId the primary key of the group
172             * @param      parentStructureId the primary key of the parent structure
173             *             (optionally {@link
174             *             com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants#DEFAULT_PARENT_STRUCTURE_ID})
175             * @param      classNameId the primary key of the class name for the
176             *             structure's related model
177             * @param      structureKey the unique string identifying the structure
178             *             (optionally <code>null</code>)
179             * @param      nameMap the structure's locales and localized names
180             * @param      descriptionMap the structure's locales and localized
181             *             descriptions
182             * @param      definition the structure's XML schema definition
183             * @param      storageType the structure's storage type. It can be "xml" or
184             *             "expando". For more information, see {@link
185             *             com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
186             * @param      type the structure's type. For more information, see {@link
187             *             com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
188             * @param      serviceContext the service context to be applied. Can set the
189             *             UUID, creation date, modification date, guest permissions,
190             *             and group permissions for the structure.
191             * @return     the structure
192             * @throws     PortalException if a user with the primary key could not be
193             *             found, if the XSD was not well-formed, or if a portal
194             *             exception occurred
195             * @deprecated As of 7.0.0, replaced by {@link #addStructure(long, long,
196             *             long, long, String, Map, Map, DDMForm, String, int,
197             *             ServiceContext)}
198             */
199            @Deprecated
200            @Override
201            public DDMStructure addStructure(
202                            long userId, long groupId, long parentStructureId, long classNameId,
203                            String structureKey, Map<Locale, String> nameMap,
204                            Map<Locale, String> descriptionMap, String definition,
205                            String storageType, int type, ServiceContext serviceContext)
206                    throws PortalException {
207    
208                    DDMXMLUtil.validateXML(definition);
209    
210                    DDMForm ddmForm = DDMFormXSDDeserializerUtil.deserialize(definition);
211    
212                    return addStructure(
213                            userId, groupId, parentStructureId, classNameId, structureKey,
214                            nameMap, descriptionMap, ddmForm, storageType, type,
215                            serviceContext);
216            }
217    
218            @Override
219            public DDMStructure addStructure(
220                            long userId, long groupId, long classNameId,
221                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
222                            DDMForm ddmForm, ServiceContext serviceContext)
223                    throws PortalException {
224    
225                    return addStructure(
226                            userId, groupId, DDMStructureConstants.DEFAULT_PARENT_STRUCTURE_ID,
227                            classNameId, null, nameMap, descriptionMap, ddmForm,
228                            PropsValues.DYNAMIC_DATA_LISTS_STORAGE_TYPE,
229                            DDMStructureConstants.TYPE_DEFAULT, serviceContext);
230            }
231    
232            /**
233             * Adds a structure referencing a default parent structure, using the portal
234             * property <code>dynamic.data.lists.storage.type</code> storage type and
235             * default structure type.
236             *
237             * @param      userId the primary key of the structure's creator/owner
238             * @param      groupId the primary key of the group
239             * @param      classNameId the primary key of the class name for the
240             *             structure's related model
241             * @param      nameMap the structure's locales and localized names
242             * @param      descriptionMap the structure's locales and localized
243             *             descriptions
244             * @param      definition the structure's XML schema definition
245             * @param      serviceContext the service context to be applied. Can set the
246             *             UUID, creation date, modification date, guest permissions,
247             *             and group permissions for the structure.
248             * @return     the structure
249             * @throws     PortalException if a user with the primary key could not be
250             *             found, if the XSD was not well-formed, or if a portal
251             *             exception occurred
252             * @deprecated As of 7.0.0, replaced by {@link #addStructure(long, long,
253             *             long, Map, Map, DDMForm, ServiceContext)}
254             */
255            @Deprecated
256            @Override
257            public DDMStructure addStructure(
258                            long userId, long groupId, long classNameId,
259                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
260                            String definition, ServiceContext serviceContext)
261                    throws PortalException {
262    
263                    return addStructure(
264                            userId, groupId, DDMStructureConstants.DEFAULT_PARENT_STRUCTURE_ID,
265                            classNameId, null, nameMap, descriptionMap, definition,
266                            PropsValues.DYNAMIC_DATA_LISTS_STORAGE_TYPE,
267                            DDMStructureConstants.TYPE_DEFAULT, serviceContext);
268            }
269    
270            @Override
271            public DDMStructure addStructure(
272                            long userId, long groupId, String parentStructureKey,
273                            long classNameId, String structureKey, Map<Locale, String> nameMap,
274                            Map<Locale, String> descriptionMap, DDMForm ddmForm,
275                            String storageType, int type, ServiceContext serviceContext)
276                    throws PortalException {
277    
278                    DDMStructure parentStructure = fetchStructure(
279                            groupId, classNameId, parentStructureKey);
280    
281                    long parentStructureId =
282                            DDMStructureConstants.DEFAULT_PARENT_STRUCTURE_ID;
283    
284                    if (parentStructure != null) {
285                            parentStructureId = parentStructure.getStructureId();
286                    }
287    
288                    return addStructure(
289                            userId, groupId, parentStructureId, classNameId, structureKey,
290                            nameMap, descriptionMap, ddmForm, storageType, type,
291                            serviceContext);
292            }
293    
294            /**
295             * Adds a structure referencing a default parent structure if the parent
296             * structure is not found.
297             *
298             * @param      userId the primary key of the structure's creator/owner
299             * @param      groupId the primary key of the group
300             * @param      parentStructureKey the unique string identifying the parent
301             *             structure (optionally <code>null</code>)
302             * @param      classNameId the primary key of the class name for the
303             *             structure's related model
304             * @param      structureKey the unique string identifying the structure
305             *             (optionally <code>null</code>)
306             * @param      nameMap the structure's locales and localized names
307             * @param      descriptionMap the structure's locales and localized
308             *             descriptions
309             * @param      definition the structure's XML schema definition
310             * @param      storageType the structure's storage type. It can be "xml" or
311             *             "expando". For more information, see {@link
312             *             com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
313             * @param      type the structure's type. For more information, see {@link
314             *             com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
315             * @param      serviceContext the service context to be applied. Can set the
316             *             UUID, creation date, modification date, guest permissions and
317             *             group permissions for the structure.
318             * @return     the structure
319             * @throws     PortalException if a user with the primary key could not be
320             *             found, if the XSD was not well-formed, or if a portal
321             *             exception occurred
322             * @deprecated As of 7.0.0, replaced by {@link #addStructure(long, long,
323             *             String, long, String, Map, Map, DDMForm, String, int,
324             *             ServiceContext)}
325             */
326            @Deprecated
327            @Override
328            public DDMStructure addStructure(
329                            long userId, long groupId, String parentStructureKey,
330                            long classNameId, String structureKey, Map<Locale, String> nameMap,
331                            Map<Locale, String> descriptionMap, String definition,
332                            String storageType, int type, ServiceContext serviceContext)
333                    throws PortalException {
334    
335                    DDMXMLUtil.validateXML(definition);
336    
337                    DDMForm ddmForm = DDMFormXSDDeserializerUtil.deserialize(definition);
338    
339                    return addStructure(
340                            userId, groupId, parentStructureKey, classNameId, structureKey,
341                            nameMap, descriptionMap, ddmForm, storageType, type,
342                            serviceContext);
343            }
344    
345            /**
346             * Adds the resources to the structure.
347             *
348             * @param  structure the structure to add resources to
349             * @param  addGroupPermissions whether to add group permissions
350             * @param  addGuestPermissions whether to add guest permissions
351             * @throws PortalException if a portal exception occurred
352             */
353            @Override
354            public void addStructureResources(
355                            DDMStructure structure, boolean addGroupPermissions,
356                            boolean addGuestPermissions)
357                    throws PortalException {
358    
359                    resourceLocalService.addResources(
360                            structure.getCompanyId(), structure.getGroupId(),
361                            structure.getUserId(), DDMStructure.class.getName(),
362                            structure.getStructureId(), false, addGroupPermissions,
363                            addGuestPermissions);
364            }
365    
366            /**
367             * Adds the model resources with the permissions to the structure.
368             *
369             * @param  structure the structure to add resources to
370             * @param  groupPermissions the group permissions to be added
371             * @param  guestPermissions the guest permissions to be added
372             * @throws PortalException if a portal exception occurred
373             */
374            @Override
375            public void addStructureResources(
376                            DDMStructure structure, String[] groupPermissions,
377                            String[] guestPermissions)
378                    throws PortalException {
379    
380                    resourceLocalService.addModelResources(
381                            structure.getCompanyId(), structure.getGroupId(),
382                            structure.getUserId(), DDMStructure.class.getName(),
383                            structure.getStructureId(), groupPermissions, guestPermissions);
384            }
385    
386            /**
387             * Copies a structure, creating a new structure with all the values
388             * extracted from the original one. The new structure supports a new name
389             * and description.
390             *
391             * @param  userId the primary key of the structure's creator/owner
392             * @param  structureId the primary key of the structure to be copied
393             * @param  nameMap the new structure's locales and localized names
394             * @param  descriptionMap the new structure's locales and localized
395             *         descriptions
396             * @param  serviceContext the service context to be applied. Can set the
397             *         UUID, creation date, modification date, guest permissions, and
398             *         group permissions for the structure.
399             * @return the new structure
400             * @throws PortalException if a portal exception occurred
401             */
402            @Override
403            public DDMStructure copyStructure(
404                            long userId, long structureId, Map<Locale, String> nameMap,
405                            Map<Locale, String> descriptionMap, ServiceContext serviceContext)
406                    throws PortalException {
407    
408                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
409                            structureId);
410    
411                    return addStructure(
412                            userId, structure.getGroupId(), structure.getParentStructureId(),
413                            structure.getClassNameId(), null, nameMap, descriptionMap,
414                            structure.getDefinition(), structure.getStorageType(),
415                            structure.getType(), serviceContext);
416            }
417    
418            @Override
419            public DDMStructure copyStructure(
420                            long userId, long structureId, ServiceContext serviceContext)
421                    throws PortalException {
422    
423                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
424                            structureId);
425    
426                    return addStructure(
427                            userId, structure.getGroupId(), structure.getParentStructureId(),
428                            structure.getClassNameId(), null, structure.getNameMap(),
429                            structure.getDescriptionMap(), structure.getDefinition(),
430                            structure.getStorageType(), structure.getType(), serviceContext);
431            }
432    
433            /**
434             * Deletes the structure and its resources.
435             *
436             * <p>
437             * Before deleting the structure, this method verifies whether the structure
438             * is required by another entity. If it is needed, an exception is thrown.
439             * </p>
440             *
441             * @param  structure the structure to be deleted
442             * @throws PortalException if a portal exception occurred
443             */
444            @Override
445            @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
446            public void deleteStructure(DDMStructure structure) throws PortalException {
447                    if (!GroupThreadLocal.isDeleteInProcess()) {
448                            if (ddmStructureLinkPersistence.countByStructureId(
449                                            structure.getStructureId()) > 0) {
450    
451                                    throw new RequiredStructureException(
452                                            RequiredStructureException.REFERENCED_STRUCTURE_LINK);
453                            }
454    
455                            if (ddmStructurePersistence.countByParentStructureId(
456                                            structure.getStructureId()) > 0) {
457    
458                                    throw new RequiredStructureException(
459                                            RequiredStructureException.REFERENCED_STRUCTURE);
460                            }
461    
462                            long classNameId = classNameLocalService.getClassNameId(
463                                    DDMStructure.class);
464    
465                            if (ddmTemplatePersistence.countByG_C_C(
466                                            structure.getGroupId(), classNameId,
467                                            structure.getPrimaryKey()) > 0) {
468    
469                                    throw new RequiredStructureException(
470                                            RequiredStructureException.REFERENCED_TEMPLATE);
471                            }
472                    }
473    
474                    // Structure
475    
476                    ddmStructurePersistence.remove(structure);
477    
478                    // Resources
479    
480                    resourceLocalService.deleteResource(
481                            structure.getCompanyId(), DDMStructure.class.getName(),
482                            ResourceConstants.SCOPE_INDIVIDUAL, structure.getStructureId());
483            }
484    
485            /**
486             * Deletes the structure and its resources.
487             *
488             * <p>
489             * Before deleting the structure, the system verifies whether the structure
490             * is required by another entity. If it is needed, an exception is thrown.
491             * </p>
492             *
493             * @param  structureId the primary key of the structure to be deleted
494             * @throws PortalException if a portal exception occurred
495             */
496            @Override
497            public void deleteStructure(long structureId) throws PortalException {
498                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
499                            structureId);
500    
501                    ddmStructureLocalService.deleteStructure(structure);
502            }
503    
504            /**
505             * Deletes the matching structure and its resources.
506             *
507             * <p>
508             * Before deleting the structure, the system verifies whether the structure
509             * is required by another entity. If it is needed, an exception is thrown.
510             * </p>
511             *
512             * @param  groupId the primary key of the group
513             * @param  classNameId the primary key of the class name for the structure's
514             *         related model
515             * @param  structureKey the unique string identifying the structure
516             * @throws PortalException if a portal exception occurred
517             */
518            @Override
519            public void deleteStructure(
520                            long groupId, long classNameId, String structureKey)
521                    throws PortalException {
522    
523                    structureKey = getStructureKey(structureKey);
524    
525                    DDMStructure structure = ddmStructurePersistence.findByG_C_S(
526                            groupId, classNameId, structureKey);
527    
528                    ddmStructureLocalService.deleteStructure(structure);
529            }
530    
531            /**
532             * Deletes all the structures of the group.
533             *
534             * <p>
535             * Before deleting the structures, the system verifies whether each
536             * structure is required by another entity. If any of the structures are
537             * needed, an exception is thrown.
538             * </p>
539             *
540             * @param  groupId the primary key of the group
541             * @throws PortalException if a portal exception occurred
542             */
543            @Override
544            public void deleteStructures(long groupId) throws PortalException {
545                    List<DDMStructure> structures = ddmStructurePersistence.findByGroupId(
546                            groupId);
547    
548                    deleteStructures(structures);
549            }
550    
551            @Override
552            public void deleteStructures(long groupId, long classNameId)
553                    throws PortalException {
554    
555                    List<DDMStructure> structures = ddmStructurePersistence.findByG_C(
556                            groupId, classNameId);
557    
558                    deleteStructures(structures);
559            }
560    
561            /**
562             * Returns the structure with the ID.
563             *
564             * @param  structureId the primary key of the structure
565             * @return the structure with the structure ID, or <code>null</code> if a
566             *         matching structure could not be found
567             */
568            @Override
569            public DDMStructure fetchStructure(long structureId) {
570                    return ddmStructurePersistence.fetchByPrimaryKey(structureId);
571            }
572    
573            /**
574             * Returns the structure matching the class name ID, structure key, and
575             * group.
576             *
577             * @param  groupId the primary key of the group
578             * @param  classNameId the primary key of the class name for the structure's
579             *         related model
580             * @param  structureKey the unique string identifying the structure
581             * @return the matching structure, or <code>null</code> if a matching
582             *         structure could not be found
583             */
584            @Override
585            public DDMStructure fetchStructure(
586                    long groupId, long classNameId, String structureKey) {
587    
588                    structureKey = getStructureKey(structureKey);
589    
590                    return ddmStructurePersistence.fetchByG_C_S(
591                            groupId, classNameId, structureKey);
592            }
593    
594            /**
595             * Returns the structure matching the class name ID, structure key, and
596             * group, optionally searching ancestor sites (that have sharing enabled)
597             * and global scoped sites.
598             *
599             * <p>
600             * This method first searches in the group. If the structure is still not
601             * found and <code>includeAncestorStructures</code> is set to
602             * <code>true</code>, this method searches the group's ancestor sites (that
603             * have sharing enabled) and lastly searches global scoped sites.
604             * </p>
605             *
606             * @param  groupId the primary key of the group
607             * @param  classNameId the primary key of the class name for the structure's
608             *         related model
609             * @param  structureKey the unique string identifying the structure
610             * @param  includeAncestorStructures whether to include ancestor sites (that
611             *         have sharing enabled) and include global scoped sites in the
612             *         search
613             * @return the matching structure, or <code>null</code> if a matching
614             *         structure could not be found
615             * @throws PortalException if a portal exception occurred
616             */
617            @Override
618            public DDMStructure fetchStructure(
619                            long groupId, long classNameId, String structureKey,
620                            boolean includeAncestorStructures)
621                    throws PortalException {
622    
623                    structureKey = getStructureKey(structureKey);
624    
625                    DDMStructure structure = ddmStructurePersistence.fetchByG_C_S(
626                            groupId, classNameId, structureKey);
627    
628                    if (structure != null) {
629                            return structure;
630                    }
631    
632                    if (!includeAncestorStructures) {
633                            return null;
634                    }
635    
636                    for (long ancestorSiteGroupId :
637                                    PortalUtil.getAncestorSiteGroupIds(groupId)) {
638    
639                            structure = ddmStructurePersistence.fetchByG_C_S(
640                                    ancestorSiteGroupId, classNameId, structureKey);
641    
642                            if (structure != null) {
643                                    return structure;
644                            }
645                    }
646    
647                    return null;
648            }
649    
650            /**
651             * @deprecated As of 6.2.0, replaced by {@link #getClassStructures(long,
652             *             long)}
653             */
654            @Deprecated
655            @Override
656            public List<DDMStructure> getClassStructures(long classNameId) {
657                    return ddmStructurePersistence.findByClassNameId(classNameId);
658            }
659    
660            /**
661             * @deprecated As of 6.2.0, replaced by {@link #getClassStructures(long,
662             *             long, int, int)}
663             */
664            @Deprecated
665            @Override
666            public List<DDMStructure> getClassStructures(
667                    long classNameId, int start, int end) {
668    
669                    return ddmStructurePersistence.findByClassNameId(
670                            classNameId, start, end);
671            }
672    
673            /**
674             * Returns all the structures matching the class name ID.
675             *
676             * @param  companyId the primary key of the structure's company
677             * @param  classNameId the primary key of the class name for the structure's
678             *         related model
679             * @return the structures matching the class name ID
680             */
681            @Override
682            public List<DDMStructure> getClassStructures(
683                    long companyId, long classNameId) {
684    
685                    return ddmStructurePersistence.findByC_C(companyId, classNameId);
686            }
687    
688            /**
689             * Returns a range of all the structures matching the class name ID.
690             *
691             * <p>
692             * Useful when paginating results. Returns a maximum of <code>end -
693             * start</code> instances. <code>start</code> and <code>end</code> are not
694             * primary keys, they are indexes in the result set. Thus, <code>0</code>
695             * refers to the first result in the set. Setting both <code>start</code>
696             * and <code>end</code> to {@link
697             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
698             * result set.
699             * </p>
700             *
701             * @param  companyId the primary key of the structure's company
702             * @param  classNameId the primary key of the class name for the structure's
703             *         related model
704             * @param  start the lower bound of the range of structures to return
705             * @param  end the upper bound of the range of structures to return (not
706             *         inclusive)
707             * @return the range of matching structures
708             */
709            @Override
710            public List<DDMStructure> getClassStructures(
711                    long companyId, long classNameId, int start, int end) {
712    
713                    return ddmStructurePersistence.findByC_C(
714                            companyId, classNameId, start, end);
715            }
716    
717            /**
718             * Returns all the structures matching the class name ID ordered by the
719             * comparator.
720             *
721             * @param  companyId the primary key of the structure's company
722             * @param  classNameId the primary key of the class name for the structure's
723             *         related model
724             * @param  orderByComparator the comparator to order the structures
725             *         (optionally <code>null</code>)
726             * @return the matching structures ordered by the comparator
727             */
728            @Override
729            public List<DDMStructure> getClassStructures(
730                    long companyId, long classNameId,
731                    OrderByComparator<DDMStructure> orderByComparator) {
732    
733                    return ddmStructurePersistence.findByC_C(
734                            companyId, classNameId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
735                            orderByComparator);
736            }
737    
738            /**
739             * @deprecated As of 6.2.0, replaced by {@link #getClassStructures(long,
740             *             long, OrderByComparator)}
741             */
742            @Deprecated
743            @Override
744            public List<DDMStructure> getClassStructures(
745                    long classNameId, OrderByComparator<DDMStructure> orderByComparator) {
746    
747                    return ddmStructurePersistence.findByClassNameId(
748                            classNameId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
749                            orderByComparator);
750            }
751    
752            /**
753             * Returns all the structures for the document library file entry type.
754             *
755             * @param  dlFileEntryTypeId the primary key of the document library file
756             *         entry type
757             * @return the structures for the document library file entry type
758             */
759            @Override
760            public List<DDMStructure> getDLFileEntryTypeStructures(
761                    long dlFileEntryTypeId) {
762    
763                    return dlFileEntryTypePersistence.getDDMStructures(dlFileEntryTypeId);
764            }
765    
766            @Override
767            public List<DDMStructure> getJournalFolderStructures(
768                            long[] groupIds, long journalFolderId, int restrictionType)
769                    throws PortalException {
770    
771                    if (restrictionType ==
772                                    JournalFolderConstants.
773                                            RESTRICTION_TYPE_DDM_STRUCTURES_AND_WORKFLOW) {
774    
775                            return journalFolderPersistence.getDDMStructures(journalFolderId);
776                    }
777    
778                    List<DDMStructure> structures = null;
779    
780                    journalFolderId =
781                            journalFolderLocalService.getOverridedDDMStructuresFolderId(
782                                    journalFolderId);
783    
784                    if (journalFolderId !=
785                                    JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
786    
787                            structures = journalFolderPersistence.getDDMStructures(
788                                    journalFolderId);
789                    }
790                    else {
791                            long classNameId = classNameLocalService.getClassNameId(
792                                    JournalArticle.class);
793    
794                            structures = ddmStructurePersistence.findByG_C(
795                                    groupIds, classNameId);
796                    }
797    
798                    return structures;
799            }
800    
801            /**
802             * Returns the structure with the ID.
803             *
804             * @param  structureId the primary key of the structure
805             * @return the structure with the ID
806             * @throws PortalException if a structure with the ID could not be found
807             */
808            @Override
809            public DDMStructure getStructure(long structureId) throws PortalException {
810                    return ddmStructurePersistence.findByPrimaryKey(structureId);
811            }
812    
813            /**
814             * Returns the structure matching the class name ID, structure key, and
815             * group.
816             *
817             * @param  groupId the primary key of the structure's group
818             * @param  classNameId the primary key of the class name for the structure's
819             *         related model
820             * @param  structureKey the unique string identifying the structure
821             * @return the matching structure
822             * @throws PortalException if a matching structure could not be found
823             */
824            @Override
825            public DDMStructure getStructure(
826                            long groupId, long classNameId, String structureKey)
827                    throws PortalException {
828    
829                    structureKey = getStructureKey(structureKey);
830    
831                    return ddmStructurePersistence.findByG_C_S(
832                            groupId, classNameId, structureKey);
833            }
834    
835            /**
836             * Returns the structure matching the class name ID, structure key, and
837             * group, optionally searching ancestor sites (that have sharing enabled)
838             * and global scoped sites.
839             *
840             * <p>
841             * This method first searches in the group. If the structure is still not
842             * found and <code>includeAncestorStructures</code> is set to
843             * <code>true</code>, this method searches the group's ancestor sites (that
844             * have sharing enabled) and lastly searches global scoped sites.
845             * </p>
846             *
847             * @param  groupId the primary key of the structure's group
848             * @param  classNameId the primary key of the class name for the structure's
849             *         related model
850             * @param  structureKey the unique string identifying the structure
851             * @param  includeAncestorStructures whether to include ancestor sites (that
852             *         have sharing enabled) and include global scoped sites in the
853             *         search in the search
854             * @return the matching structure
855             * @throws PortalException if a matching structure could not be found
856             */
857            @Override
858            public DDMStructure getStructure(
859                            long groupId, long classNameId, String structureKey,
860                            boolean includeAncestorStructures)
861                    throws PortalException {
862    
863                    structureKey = getStructureKey(structureKey);
864    
865                    DDMStructure structure = ddmStructurePersistence.fetchByG_C_S(
866                            groupId, classNameId, structureKey);
867    
868                    if (structure != null) {
869                            return structure;
870                    }
871    
872                    if (!includeAncestorStructures) {
873                            throw new NoSuchStructureException(
874                                    "No DDMStructure exists with the structure key " +
875                                            structureKey);
876                    }
877    
878                    for (long curGroupId : PortalUtil.getAncestorSiteGroupIds(groupId)) {
879                            structure = ddmStructurePersistence.fetchByG_C_S(
880                                    curGroupId, classNameId, structureKey);
881    
882                            if (structure != null) {
883                                    return structure;
884                            }
885                    }
886    
887                    throw new NoSuchStructureException(
888                            "No DDMStructure exists with the structure key " +
889                                    structureKey + " in the ancestor groups");
890            }
891    
892            /**
893             * Returns all the structures matching the group, name, and description.
894             *
895             * @param  groupId the primary key of the structure's group
896             * @param  name the structure's name
897             * @param  description the structure's description
898             * @return the matching structures
899             */
900            @Override
901            public List<DDMStructure> getStructure(
902                    long groupId, String name, String description) {
903    
904                    return ddmStructurePersistence.findByG_N_D(groupId, name, description);
905            }
906    
907            /**
908             * @deprecated As of 6.2.0, replaced by {@link #getStructures}
909             */
910            @Deprecated
911            @Override
912            public List<DDMStructure> getStructureEntries() {
913                    return getStructures();
914            }
915    
916            /**
917             * @deprecated As of 6.2.0, replaced by {@link #getStructures(long)}
918             */
919            @Deprecated
920            @Override
921            public List<DDMStructure> getStructureEntries(long groupId) {
922                    return getStructures(groupId);
923            }
924    
925            /**
926             * @deprecated As of 6.2.0, replaced by {@link #getStructures(long, int,
927             *             int)}
928             */
929            @Deprecated
930            @Override
931            public List<DDMStructure> getStructureEntries(
932                    long groupId, int start, int end) {
933    
934                    return getStructures(groupId, start, end);
935            }
936    
937            /**
938             * Returns all the structures present in the system.
939             *
940             * @return the structures present in the system
941             */
942            @Override
943            public List<DDMStructure> getStructures() {
944                    return ddmStructurePersistence.findAll();
945            }
946    
947            /**
948             * Returns all the structures present in the group.
949             *
950             * @param  groupId the primary key of the group
951             * @return the structures present in the group
952             */
953            @Override
954            public List<DDMStructure> getStructures(long groupId) {
955                    return ddmStructurePersistence.findByGroupId(groupId);
956            }
957    
958            /**
959             * Returns a range of all the structures belonging to the group.
960             *
961             * <p>
962             * Useful when paginating results. Returns a maximum of <code>end -
963             * start</code> instances. <code>start</code> and <code>end</code> are not
964             * primary keys, they are indexes in the result set. Thus, <code>0</code>
965             * refers to the first result in the set. Setting both <code>start</code>
966             * and <code>end</code> to {@link
967             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
968             * result set.
969             * </p>
970             *
971             * @param  groupId the primary key of the group
972             * @param  start the lower bound of the range of structures to return
973             * @param  end the upper bound of the range of structures to return (not
974             *         inclusive)
975             * @return the range of matching structures
976             */
977            @Override
978            public List<DDMStructure> getStructures(long groupId, int start, int end) {
979                    return ddmStructurePersistence.findByGroupId(groupId, start, end);
980            }
981    
982            /**
983             * Returns all the structures matching class name ID and group.
984             *
985             * @param  groupId the primary key of the group
986             * @param  classNameId the primary key of the class name for the structure's
987             *         related model
988             * @return the matching structures
989             */
990            @Override
991            public List<DDMStructure> getStructures(long groupId, long classNameId) {
992                    return ddmStructurePersistence.findByG_C(groupId, classNameId);
993            }
994    
995            /**
996             * Returns a range of all the structures that match the class name ID and
997             * group.
998             *
999             * <p>
1000             * Useful when paginating results. Returns a maximum of <code>end -
1001             * start</code> instances. <code>start</code> and <code>end</code> are not
1002             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1003             * refers to the first result in the set. Setting both <code>start</code>
1004             * and <code>end</code> to {@link
1005             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1006             * result set.
1007             * </p>
1008             *
1009             * @param  groupId the primary key of the group
1010             * @param  classNameId the primary key of the class name for the structure's
1011             *         related model
1012             * @param  start the lower bound of the range of structures to return
1013             * @param  end the upper bound of the range of structures to return (not
1014             *         inclusive)
1015             * @return the range of matching structures
1016             */
1017            @Override
1018            public List<DDMStructure> getStructures(
1019                    long groupId, long classNameId, int start, int end) {
1020    
1021                    return ddmStructurePersistence.findByG_C(
1022                            groupId, classNameId, start, end);
1023            }
1024    
1025            /**
1026             * Returns an ordered range of all the structures matching the class name ID
1027             * and group.
1028             *
1029             * <p>
1030             * Useful when paginating results. Returns a maximum of <code>end -
1031             * start</code> instances. <code>start</code> and <code>end</code> are not
1032             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1033             * refers to the first result in the set. Setting both <code>start</code>
1034             * and <code>end</code> to {@link
1035             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1036             * result set.
1037             * </p>
1038             *
1039             * @param  groupId the primary key of the group
1040             * @param  classNameId the primary key of the class name for the structure's
1041             *         related model
1042             * @param  start the lower bound of the range of structures to return
1043             * @param  end the upper bound of the range of structures to return (not
1044             *         inclusive)
1045             * @param  orderByComparator the comparator to order the structures
1046             *         (optionally <code>null</code>)
1047             * @return the range of matching structures ordered by the comparator
1048             */
1049            @Override
1050            public List<DDMStructure> getStructures(
1051                    long groupId, long classNameId, int start, int end,
1052                    OrderByComparator<DDMStructure> orderByComparator) {
1053    
1054                    return ddmStructurePersistence.findByG_C(
1055                            groupId, classNameId, start, end, orderByComparator);
1056            }
1057    
1058            @Override
1059            public List<DDMStructure> getStructures(
1060                    long groupId, String name, String description) {
1061    
1062                    return ddmStructurePersistence.findByG_N_D(groupId, name, description);
1063            }
1064    
1065            /**
1066             * Returns all the structures belonging to the groups.
1067             *
1068             * @param  groupIds the primary keys of the groups
1069             * @return the structures belonging to the groups
1070             */
1071            @Override
1072            public List<DDMStructure> getStructures(long[] groupIds) {
1073                    return ddmStructurePersistence.findByGroupId(groupIds);
1074            }
1075    
1076            /**
1077             * Returns all the structures matching the class name ID and belonging to
1078             * the groups.
1079             *
1080             * @param  groupIds the primary keys of the groups
1081             * @param  classNameId the primary key of the class name for the structure's
1082             *         related model
1083             * @return the matching structures
1084             */
1085            @Override
1086            public List<DDMStructure> getStructures(long[] groupIds, long classNameId) {
1087                    return ddmStructurePersistence.findByG_C(groupIds, classNameId);
1088            }
1089    
1090            /**
1091             * Returns a range of all the structures matching the class name ID and
1092             * belonging to the groups.
1093             *
1094             * <p>
1095             * Useful when paginating results. Returns a maximum of <code>end -
1096             * start</code> instances. <code>start</code> and <code>end</code> are not
1097             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1098             * refers to the first result in the set. Setting both <code>start</code>
1099             * and <code>end</code> to {@link
1100             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1101             * result set.
1102             * </p>
1103             *
1104             * @param  groupIds the primary keys of the groups
1105             * @param  classNameId the primary key of the class name for the structure's
1106             *         related model
1107             * @param  start the lower bound of the range of structures to return
1108             * @param  end the upper bound of the range of structures to return (not
1109             *         inclusive)
1110             * @return the range of matching structures
1111             */
1112            @Override
1113            public List<DDMStructure> getStructures(
1114                    long[] groupIds, long classNameId, int start, int end) {
1115    
1116                    return ddmStructurePersistence.findByG_C(
1117                            groupIds, classNameId, start, end);
1118            }
1119    
1120            /**
1121             * Returns the number of structures belonging to the group.
1122             *
1123             * @param  groupId the primary key of the group
1124             * @return the number of structures belonging to the group
1125             */
1126            @Override
1127            public int getStructuresCount(long groupId) {
1128                    return ddmStructurePersistence.countByGroupId(groupId);
1129            }
1130    
1131            /**
1132             * Returns the number of structures matching the class name ID and group.
1133             *
1134             * @param  groupId the primary key of the group
1135             * @param  classNameId the primary key of the class name for the structure's
1136             *         related model
1137             * @return the number of matching structures
1138             */
1139            @Override
1140            public int getStructuresCount(long groupId, long classNameId) {
1141                    return ddmStructurePersistence.countByG_C(groupId, classNameId);
1142            }
1143    
1144            /**
1145             * Returns the number of structures matching the class name ID and belonging
1146             * to the groups.
1147             *
1148             * @param  groupIds the primary keys of the groups
1149             * @param  classNameId the primary key of the class name for the structure's
1150             *         related model
1151             * @return the number of matching structures
1152             */
1153            @Override
1154            public int getStructuresCount(long[] groupIds, long classNameId) {
1155                    return ddmStructurePersistence.countByG_C(groupIds, classNameId);
1156            }
1157    
1158            /**
1159             * Returns an ordered range of all the structures matching the groups and
1160             * class name IDs, and matching the keywords in the structure names and
1161             * descriptions.
1162             *
1163             * <p>
1164             * Useful when paginating results. Returns a maximum of <code>end -
1165             * start</code> instances. <code>start</code> and <code>end</code> are not
1166             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1167             * refers to the first result in the set. Setting both <code>start</code>
1168             * and <code>end</code> to {@link
1169             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1170             * result set.
1171             * </p>
1172             *
1173             * @param  companyId the primary key of the structure's company
1174             * @param  groupIds the primary keys of the groups
1175             * @param  classNameIds the primary keys of the class names of the models
1176             *         the structures are related to
1177             * @param  keywords the keywords (space separated), which may occur in the
1178             *         structure's name or description (optionally <code>null</code>)
1179             * @param  start the lower bound of the range of structures to return
1180             * @param  end the upper bound of the range of structures to return (not
1181             *         inclusive)
1182             * @param  orderByComparator the comparator to order the structures
1183             *         (optionally <code>null</code>)
1184             * @return the range of matching structures ordered by the comparator
1185             */
1186            @Override
1187            public List<DDMStructure> search(
1188                    long companyId, long[] groupIds, long[] classNameIds, String keywords,
1189                    int start, int end, OrderByComparator<DDMStructure> orderByComparator) {
1190    
1191                    return ddmStructureFinder.findByKeywords(
1192                            companyId, groupIds, classNameIds, keywords, start, end,
1193                            orderByComparator);
1194            }
1195    
1196            /**
1197             * Returns an ordered range of all the structures matching the groups, class
1198             * name IDs, name keyword, description keyword, storage type, and type.
1199             *
1200             * <p>
1201             * Useful when paginating results. Returns a maximum of <code>end -
1202             * start</code> instances. <code>start</code> and <code>end</code> are not
1203             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1204             * refers to the first result in the set. Setting both <code>start</code>
1205             * and <code>end</code> to {@link
1206             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1207             * result set.
1208             * </p>
1209             *
1210             * @param  companyId the primary key of the structure's company
1211             * @param  groupIds the primary keys of the groups
1212             * @param  classNameIds the primary keys of the class names of the models
1213             *         the structures are related to
1214             * @param  name the name keywords
1215             * @param  description the description keywords
1216             * @param  storageType the structure's storage type. It can be "xml" or
1217             *         "expando". For more information, see {@link
1218             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
1219             * @param  type the structure's type. For more information, see {@link
1220             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
1221             * @param  andOperator whether every field must match its keywords, or just
1222             *         one field
1223             * @param  start the lower bound of the range of structures to return
1224             * @param  end the upper bound of the range of structures to return (not
1225             *         inclusive)
1226             * @param  orderByComparator the comparator to order the structures
1227             *         (optionally <code>null</code>)
1228             * @return the range of matching structures ordered by the comparator
1229             */
1230            @Override
1231            public List<DDMStructure> search(
1232                    long companyId, long[] groupIds, long[] classNameIds, String name,
1233                    String description, String storageType, int type, boolean andOperator,
1234                    int start, int end, OrderByComparator<DDMStructure> orderByComparator) {
1235    
1236                    return ddmStructureFinder.findByC_G_C_N_D_S_T(
1237                            companyId, groupIds, classNameIds, name, description, storageType,
1238                            type, andOperator, start, end, orderByComparator);
1239            }
1240    
1241            /**
1242             * Returns the number of structures matching the groups and class name IDs,
1243             * and matching the keywords in the structure names and descriptions.
1244             *
1245             * @param  companyId the primary key of the structure's company
1246             * @param  groupIds the primary keys of the groups
1247             * @param  classNameIds the primary keys of the class names of the models
1248             *         the structures are related to
1249             * @param  keywords the keywords (space separated), which may occur in the
1250             *         structure's name or description (optionally <code>null</code>)
1251             * @return the number of matching structures
1252             */
1253            @Override
1254            public int searchCount(
1255                    long companyId, long[] groupIds, long[] classNameIds, String keywords) {
1256    
1257                    return ddmStructureFinder.countByKeywords(
1258                            companyId, groupIds, classNameIds, keywords);
1259            }
1260    
1261            /**
1262             * Returns the number of structures matching the groups, class name IDs,
1263             * name keyword, description keyword, storage type, and type
1264             *
1265             * @param  companyId the primary key of the structure's company
1266             * @param  groupIds the primary keys of the groups
1267             * @param  classNameIds the primary keys of the class names of the models
1268             *         the structure's are related to
1269             * @param  name the name keywords
1270             * @param  description the description keywords
1271             * @param  storageType the structure's storage type. It can be "xml" or
1272             *         "expando". For more information, see {@link
1273             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
1274             * @param  type the structure's type. For more information, see {@link
1275             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
1276             * @param  andOperator whether every field must match its keywords, or just
1277             *         one field
1278             * @return the number of matching structures
1279             */
1280            @Override
1281            public int searchCount(
1282                    long companyId, long[] groupIds, long[] classNameIds, String name,
1283                    String description, String storageType, int type, boolean andOperator) {
1284    
1285                    return ddmStructureFinder.countByC_G_C_N_D_S_T(
1286                            companyId, groupIds, classNameIds, name, description, storageType,
1287                            type, andOperator);
1288            }
1289    
1290            @Override
1291            public DDMStructure updateDDMForm(
1292                            long structureId, DDMForm ddmForm, ServiceContext serviceContext)
1293                    throws PortalException {
1294    
1295                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
1296                            structureId);
1297    
1298                    return doUpdateStructure(
1299                            structure.getParentStructureId(), structure.getNameMap(),
1300                            structure.getDescriptionMap(), ddmForm, serviceContext, structure);
1301            }
1302    
1303            @Override
1304            public DDMStructure updateStructure(
1305                            long groupId, long parentStructureId, long classNameId,
1306                            String structureKey, Map<Locale, String> nameMap,
1307                            Map<Locale, String> descriptionMap, DDMForm ddmForm,
1308                            ServiceContext serviceContext)
1309                    throws PortalException {
1310    
1311                    structureKey = getStructureKey(structureKey);
1312    
1313                    DDMStructure structure = ddmStructurePersistence.findByG_C_S(
1314                            groupId, classNameId, structureKey);
1315    
1316                    return doUpdateStructure(
1317                            parentStructureId, nameMap, descriptionMap, ddmForm, serviceContext,
1318                            structure);
1319            }
1320    
1321            /**
1322             * Updates the structure matching the class name ID, structure key, and
1323             * group, replacing its old parent structure, name map, description map, and
1324             * XSD with new ones.
1325             *
1326             * @param      groupId the primary key of the group
1327             * @param      parentStructureId the primary key of the new parent structure
1328             * @param      classNameId the primary key of the class name for the
1329             *             structure's related model
1330             * @param      structureKey the unique string identifying the structure
1331             * @param      nameMap the structure's new locales and localized names
1332             * @param      descriptionMap the structure's new locales and localized
1333             *             description
1334             * @param      definition the structure's new XML schema definition
1335             * @param      serviceContext the service context to be applied. Can set the
1336             *             structure's modification date.
1337             * @return     the updated structure
1338             * @throws     PortalException if a matching structure could not be found,
1339             *             if the XSD was not well-formed, or if a portal exception
1340             *             occurred
1341             * @deprecated As of 7.0.0, replaced by {@link #updateStructure(long, long,
1342             *             long, String, Map, Map, DDMForm, ServiceContext)}
1343             */
1344            @Deprecated
1345            @Override
1346            public DDMStructure updateStructure(
1347                            long groupId, long parentStructureId, long classNameId,
1348                            String structureKey, Map<Locale, String> nameMap,
1349                            Map<Locale, String> descriptionMap, String definition,
1350                            ServiceContext serviceContext)
1351                    throws PortalException {
1352    
1353                    DDMXMLUtil.validateXML(definition);
1354    
1355                    DDMForm ddmForm = DDMFormXSDDeserializerUtil.deserialize(definition);
1356    
1357                    structureKey = getStructureKey(structureKey);
1358    
1359                    DDMStructure structure = ddmStructurePersistence.findByG_C_S(
1360                            groupId, classNameId, structureKey);
1361    
1362                    return doUpdateStructure(
1363                            parentStructureId, nameMap, descriptionMap, ddmForm, serviceContext,
1364                            structure);
1365            }
1366    
1367            @Override
1368            public DDMStructure updateStructure(
1369                            long structureId, long parentStructureId,
1370                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
1371                            DDMForm ddmForm, ServiceContext serviceContext)
1372                    throws PortalException {
1373    
1374                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
1375                            structureId);
1376    
1377                    return doUpdateStructure(
1378                            parentStructureId, nameMap, descriptionMap, ddmForm, serviceContext,
1379                            structure);
1380            }
1381    
1382            /**
1383             * Updates the structure matching the structure ID, replacing its old parent
1384             * structure, name map, description map, and XSD with new ones.
1385             *
1386             * @param      structureId the primary key of the structure
1387             * @param      parentStructureId the primary key of the new parent structure
1388             * @param      nameMap the structure's new locales and localized names
1389             * @param      descriptionMap the structure's new locales and localized
1390             *             descriptions
1391             * @param      definition the structure's new XML schema definition
1392             * @param      serviceContext the service context to be applied. Can set the
1393             *             structure's modification date.
1394             * @return     the updated structure
1395             * @throws     PortalException if a matching structure could not be found,
1396             *             if the XSD was not well-formed, or if a portal exception
1397             *             occurred
1398             * @deprecated As of 7.0.0, replaced by {@link #updateStructure(long, long,
1399             *             Map, Map, DDMForm, ServiceContext)}
1400             */
1401            @Deprecated
1402            @Override
1403            public DDMStructure updateStructure(
1404                            long structureId, long parentStructureId,
1405                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
1406                            String definition, ServiceContext serviceContext)
1407                    throws PortalException {
1408    
1409                    DDMXMLUtil.validateXML(definition);
1410    
1411                    DDMForm ddmForm = DDMFormXSDDeserializerUtil.deserialize(definition);
1412    
1413                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
1414                            structureId);
1415    
1416                    return doUpdateStructure(
1417                            parentStructureId, nameMap, descriptionMap, ddmForm, serviceContext,
1418                            structure);
1419            }
1420    
1421            /**
1422             * Updates the structure matching the structure ID, replacing its XSD with a
1423             * new one.
1424             *
1425             * @param      structureId the primary key of the structure
1426             * @param      definition the structure's new XML schema definition
1427             * @param      serviceContext the service context to be applied. Can set the
1428             *             structure's modification date.
1429             * @return     the updated structure
1430             * @throws     PortalException if a matching structure could not be found,
1431             *             if the XSD was not well-formed, or if a portal exception
1432             *             occurred
1433             * @deprecated As of 7.0.0, replaced by {@link #updateDDMForm(long, String,
1434             *             ServiceContext)}
1435             */
1436            @Deprecated
1437            @Override
1438            public DDMStructure updateXSD(
1439                            long structureId, String definition, ServiceContext serviceContext)
1440                    throws PortalException {
1441    
1442                    DDMXMLUtil.validateXML(definition);
1443    
1444                    DDMForm ddmForm = DDMFormXSDDeserializerUtil.deserialize(definition);
1445    
1446                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
1447                            structureId);
1448    
1449                    return doUpdateStructure(
1450                            structure.getParentStructureId(), structure.getNameMap(),
1451                            structure.getDescriptionMap(), ddmForm, serviceContext, structure);
1452            }
1453    
1454            protected DDMStructureVersion addStructureVersion(
1455                    DDMStructure structure, String version) {
1456    
1457                    long structureVersionId = counterLocalService.increment();
1458    
1459                    DDMStructureVersion structureVersion =
1460                            ddmStructureVersionPersistence.create(structureVersionId);
1461    
1462                    structureVersion.setGroupId(structure.getGroupId());
1463                    structureVersion.setCompanyId(structure.getCompanyId());
1464                    structureVersion.setUserId(structure.getUserId());
1465                    structureVersion.setUserName(structure.getUserName());
1466                    structureVersion.setCreateDate(structure.getModifiedDate());
1467                    structureVersion.setStructureId(structure.getStructureId());
1468                    structureVersion.setVersion(version);
1469                    structureVersion.setName(structure.getName());
1470                    structureVersion.setDescription(structure.getDescription());
1471                    structureVersion.setDefinition(structure.getDefinition());
1472                    structureVersion.setStorageType(structure.getStorageType());
1473                    structureVersion.setType(structure.getType());
1474    
1475                    ddmStructureVersionPersistence.update(structureVersion);
1476    
1477                    return structureVersion;
1478            }
1479    
1480            protected Set<Long> deleteStructures(List<DDMStructure> structures)
1481                    throws PortalException {
1482    
1483                    Set<Long> deletedStructureIds = new HashSet<Long>();
1484    
1485                    for (DDMStructure structure : structures) {
1486                            if (deletedStructureIds.contains(structure.getStructureId())) {
1487                                    continue;
1488                            }
1489    
1490                            if (!GroupThreadLocal.isDeleteInProcess()) {
1491                                    List<DDMStructure> childDDMStructures =
1492                                            ddmStructurePersistence.findByParentStructureId(
1493                                                    structure.getStructureId());
1494    
1495                                    deletedStructureIds.addAll(
1496                                            deleteStructures(childDDMStructures));
1497                            }
1498    
1499                            ddmStructureLocalService.deleteStructure(structure);
1500    
1501                            deletedStructureIds.add(structure.getStructureId());
1502                    }
1503    
1504                    return deletedStructureIds;
1505            }
1506    
1507            protected DDMStructure doUpdateStructure(
1508                            long parentStructureId, Map<Locale, String> nameMap,
1509                            Map<Locale, String> descriptionMap, DDMForm ddmForm,
1510                            ServiceContext serviceContext, DDMStructure structure)
1511                    throws PortalException {
1512    
1513                    // Structure
1514    
1515                    DDMForm parentDDMForm = getParentDDMForm(parentStructureId);
1516    
1517                    validate(nameMap, parentDDMForm, ddmForm);
1518    
1519                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
1520                    structure.setParentStructureId(parentStructureId);
1521    
1522                    DDMStructureVersion latestStructureVersion =
1523                            ddmStructureVersionLocalService.getLatestStructureVersion(
1524                                    structure.getStructureId());
1525    
1526                    String version = getNextVersion(
1527                            latestStructureVersion.getVersion(), false);
1528    
1529                    structure.setVersion(version);
1530                    structure.setNameMap(nameMap);
1531                    structure.setDescriptionMap(descriptionMap);
1532                    structure.setDefinition(DDMFormXSDSerializerUtil.serialize(ddmForm));
1533    
1534                    ddmStructurePersistence.update(structure);
1535    
1536                    // Structure templates
1537    
1538                    syncStructureTemplatesFields(structure);
1539    
1540                    // Structure version
1541    
1542                    addStructureVersion(structure, version);
1543    
1544                    // Indexer
1545    
1546                    Indexer indexer = IndexerRegistryUtil.getIndexer(
1547                            structure.getClassName());
1548    
1549                    if (indexer != null) {
1550                            List<Long> ddmStructureIds = getChildrenStructureIds(
1551                                    structure.getGroupId(), structure.getStructureId());
1552    
1553                            indexer.reindexDDMStructures(ddmStructureIds);
1554                    }
1555    
1556                    return structure;
1557            }
1558    
1559            protected void getChildrenStructureIds(
1560                            List<Long> structureIds, long groupId, long parentStructureId)
1561                    throws PortalException {
1562    
1563                    List<DDMStructure> structures = ddmStructurePersistence.findByG_P(
1564                            groupId, parentStructureId);
1565    
1566                    for (DDMStructure structure : structures) {
1567                            structureIds.add(structure.getStructureId());
1568    
1569                            getChildrenStructureIds(
1570                                    structureIds, structure.getGroupId(),
1571                                    structure.getStructureId());
1572                    }
1573            }
1574    
1575            protected List<Long> getChildrenStructureIds(long groupId, long structureId)
1576                    throws PortalException {
1577    
1578                    List<Long> structureIds = new ArrayList<Long>();
1579    
1580                    getChildrenStructureIds(structureIds, groupId, structureId);
1581    
1582                    structureIds.add(0, structureId);
1583    
1584                    return structureIds;
1585            }
1586    
1587            protected Set<String> getDDMFormFieldsNames(DDMForm ddmForm) {
1588                    Map<String, DDMFormField> ddmFormFieldsMap =
1589                            ddmForm.getDDMFormFieldsMap(true);
1590    
1591                    Set<String> ddmFormFieldsNames = new HashSet<String>(
1592                            ddmFormFieldsMap.size());
1593    
1594                    for (String ddmFormFieldName : ddmFormFieldsMap.keySet()) {
1595                            if (ddmFormFieldName.startsWith(StringPool.UNDERLINE)) {
1596                                    continue;
1597                            }
1598    
1599                            ddmFormFieldsNames.add(StringUtil.toLowerCase(ddmFormFieldName));
1600                    }
1601    
1602                    return ddmFormFieldsNames;
1603            }
1604    
1605            protected String getNextVersion(String version, boolean majorVersion) {
1606                    int[] versionParts = StringUtil.split(version, StringPool.PERIOD, 0);
1607    
1608                    if (majorVersion) {
1609                            versionParts[0]++;
1610                            versionParts[1] = 0;
1611                    }
1612                    else {
1613                            versionParts[1]++;
1614                    }
1615    
1616                    return versionParts[0] + StringPool.PERIOD + versionParts[1];
1617            }
1618    
1619            protected DDMForm getParentDDMForm(long parentStructureId) {
1620                    DDMStructure parentStructure =
1621                            ddmStructurePersistence.fetchByPrimaryKey(parentStructureId);
1622    
1623                    if (parentStructure == null) {
1624                            return null;
1625                    }
1626    
1627                    return parentStructure.getFullHierarchyDDMForm();
1628            }
1629    
1630            protected String getStructureKey(String structureKey) {
1631                    if (structureKey != null) {
1632                            structureKey = structureKey.trim();
1633    
1634                            return StringUtil.toUpperCase(structureKey);
1635                    }
1636    
1637                    return StringPool.BLANK;
1638            }
1639    
1640            protected List<DDMTemplate> getStructureTemplates(
1641                    DDMStructure structure, String type) {
1642    
1643                    long classNameId = classNameLocalService.getClassNameId(
1644                            DDMStructure.class);
1645    
1646                    return ddmTemplateLocalService.getTemplates(
1647                            structure.getGroupId(), classNameId, structure.getStructureId(),
1648                            type);
1649            }
1650    
1651            protected void syncStructureTemplatesFields(final DDMStructure structure) {
1652                    TransactionCommitCallbackRegistryUtil.registerCallback(
1653                            new Callable<Void>() {
1654    
1655                                    @Override
1656                                    public Void call() throws Exception {
1657                                            DDMFormTemplateSynchonizer ddmFormTemplateSynchonizer =
1658                                                    new DDMFormTemplateSynchonizer(structure.getDDMForm());
1659    
1660                                            List<DDMTemplate> templates = getStructureTemplates(
1661                                                    structure, DDMTemplateConstants.TEMPLATE_TYPE_FORM);
1662    
1663                                            ddmFormTemplateSynchonizer.setDDMFormTemplates(templates);
1664    
1665                                            ddmFormTemplateSynchonizer.synchronize();
1666    
1667                                            return null;
1668                                    }
1669    
1670                            });
1671            }
1672    
1673            protected void validate(DDMForm parentDDMForm, DDMForm ddmForm)
1674                    throws PortalException {
1675    
1676                    Set<String> commonDDMFormFieldNames = SetUtil.intersect(
1677                            getDDMFormFieldsNames(parentDDMForm),
1678                            getDDMFormFieldsNames(ddmForm));
1679    
1680                    if (!commonDDMFormFieldNames.isEmpty()) {
1681                            throw new StructureDuplicateElementException();
1682                    }
1683            }
1684    
1685            protected void validate(
1686                            long groupId, long parentStructureId, long classNameId,
1687                            String structureKey, Map<Locale, String> nameMap, DDMForm ddmForm)
1688                    throws PortalException {
1689    
1690                    structureKey = getStructureKey(structureKey);
1691    
1692                    DDMStructure structure = ddmStructurePersistence.fetchByG_C_S(
1693                            groupId, classNameId, structureKey);
1694    
1695                    if (structure != null) {
1696                            StructureDuplicateStructureKeyException sdske =
1697                                    new StructureDuplicateStructureKeyException();
1698    
1699                            sdske.setStructureKey(structure.getStructureKey());
1700    
1701                            throw sdske;
1702                    }
1703    
1704                    DDMForm parentDDMForm = getParentDDMForm(parentStructureId);
1705    
1706                    validate(nameMap, parentDDMForm, ddmForm);
1707            }
1708    
1709            protected void validate(
1710                            Map<Locale, String> nameMap, DDMForm parentDDMForm, DDMForm ddmForm)
1711                    throws PortalException {
1712    
1713                    try {
1714                            validate(nameMap, ddmForm.getDefaultLocale());
1715    
1716                            if (parentDDMForm != null) {
1717                                    validate(parentDDMForm, ddmForm);
1718                            }
1719                    }
1720                    catch (LocaleException le) {
1721                            throw le;
1722                    }
1723                    catch (StructureDuplicateElementException sdee) {
1724                            throw sdee;
1725                    }
1726                    catch (StructureNameException sne) {
1727                            throw sne;
1728                    }
1729                    catch (StructureDefinitionException sde) {
1730                            throw sde;
1731                    }
1732                    catch (Exception e) {
1733                            throw new StructureDefinitionException();
1734                    }
1735            }
1736    
1737            protected void validate(
1738                            Map<Locale, String> nameMap, Locale contentDefaultLocale)
1739                    throws PortalException {
1740    
1741                    String name = nameMap.get(contentDefaultLocale);
1742    
1743                    if (Validator.isNull(name)) {
1744                            throw new StructureNameException();
1745                    }
1746    
1747                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
1748    
1749                    if (!ArrayUtil.contains(availableLocales, contentDefaultLocale)) {
1750                            Long companyId = CompanyThreadLocal.getCompanyId();
1751    
1752                            LocaleException le = new LocaleException(
1753                                    LocaleException.TYPE_CONTENT,
1754                                    "The locale " + contentDefaultLocale +
1755                                            " is not available in company " + companyId);
1756    
1757                            le.setSourceAvailableLocales(new Locale[] {contentDefaultLocale});
1758                            le.setTargetAvailableLocales(availableLocales);
1759    
1760                            throw le;
1761                    }
1762            }
1763    
1764    }