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