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