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,
1363             *             if the XSD was not well-formed, or if a portal exception
1364             *             occurred
1365             * @throws     SystemException if a system exception occurred
1366             *
1367             * @deprecated As of 6.2.0, with no direct replacement
1368             */
1369            @Override
1370            public void updateXSDFieldMetadata(
1371                            long structureId, String fieldName, String metadataEntryName,
1372                            String metadataEntryValue, ServiceContext serviceContext)
1373                    throws PortalException, SystemException {
1374    
1375                    DDMStructure ddmStructure = fetchDDMStructure(structureId);
1376    
1377                    if (ddmStructure == null) {
1378                            return;
1379                    }
1380    
1381                    String xsd = ddmStructure.getXsd();
1382    
1383                    try {
1384                            Document document = SAXReaderUtil.read(xsd);
1385    
1386                            Element rootElement = document.getRootElement();
1387    
1388                            List<Element> dynamicElementElements = rootElement.elements(
1389                                    "dynamic-element");
1390    
1391                            for (Element dynamicElementElement : dynamicElementElements) {
1392                                    String dynamicElementElementFieldName = GetterUtil.getString(
1393                                            dynamicElementElement.attributeValue("name"));
1394    
1395                                    if (!dynamicElementElementFieldName.equals(fieldName)) {
1396                                            continue;
1397                                    }
1398    
1399                                    List<Element> metadataElements = dynamicElementElement.elements(
1400                                            "meta-data");
1401    
1402                                    for (Element metadataElement : metadataElements) {
1403                                            List<Element> metadataEntryElements =
1404                                                    metadataElement.elements();
1405    
1406                                            for (Element metadataEntryElement : metadataEntryElements) {
1407                                                    String metadataEntryElementName = GetterUtil.getString(
1408                                                            metadataEntryElement.attributeValue("name"));
1409    
1410                                                    if (metadataEntryElementName.equals(
1411                                                                    metadataEntryName)) {
1412    
1413                                                            metadataEntryElement.setText(metadataEntryValue);
1414                                                    }
1415                                            }
1416                                    }
1417                            }
1418    
1419                            updateXSD(structureId, document.asXML(), serviceContext);
1420                    }
1421                    catch (DocumentException de) {
1422                            throw new SystemException(de);
1423                    }
1424            }
1425    
1426            protected void appendNewStructureRequiredFields(
1427                    DDMStructure structure, Document templateDocument) {
1428    
1429                    String xsd = structure.getXsd();
1430    
1431                    Document structureDocument = null;
1432    
1433                    try {
1434                            structureDocument = SAXReaderUtil.read(xsd);
1435                    }
1436                    catch (DocumentException de) {
1437                            if (_log.isWarnEnabled()) {
1438                                    _log.warn(de, de);
1439                            }
1440    
1441                            return;
1442                    }
1443    
1444                    Element templateElement = templateDocument.getRootElement();
1445    
1446                    XPath structureXPath = SAXReaderUtil.createXPath(
1447                            "//dynamic-element[.//meta-data/entry[@name=\"required\"]=" +
1448                                    "\"true\"]");
1449    
1450                    List<Node> nodes = structureXPath.selectNodes(structureDocument);
1451    
1452                    for (Node node : nodes) {
1453                            Element element = (Element)node;
1454    
1455                            String name = element.attributeValue("name");
1456    
1457                            name = HtmlUtil.escapeXPathAttribute(name);
1458    
1459                            XPath templateXPath = SAXReaderUtil.createXPath(
1460                                    "//dynamic-element[@name=" + name + "]");
1461    
1462                            if (!templateXPath.booleanValueOf(templateDocument)) {
1463                                    templateElement.add(element.createCopy());
1464                            }
1465                    }
1466            }
1467    
1468            protected Set<Long> deleteStructures(List<DDMStructure> structures)
1469                    throws PortalException, SystemException {
1470    
1471                    Set<Long> deletedStructureIds = new HashSet<Long>();
1472    
1473                    for (DDMStructure structure : structures) {
1474                            if (deletedStructureIds.contains(structure.getStructureId())) {
1475                                    continue;
1476                            }
1477    
1478                            if (!GroupThreadLocal.isDeleteInProcess()) {
1479                                    List<DDMStructure> childDDMStructures =
1480                                            ddmStructurePersistence.findByParentStructureId(
1481                                                    structure.getStructureId());
1482    
1483                                    deletedStructureIds.addAll(
1484                                            deleteStructures(childDDMStructures));
1485                            }
1486    
1487                            ddmStructureLocalService.deleteStructure(structure);
1488    
1489                            deletedStructureIds.add(structure.getStructureId());
1490                    }
1491    
1492                    return deletedStructureIds;
1493            }
1494    
1495            protected DDMStructure doUpdateStructure(
1496                            long parentStructureId, Map<Locale, String> nameMap,
1497                            Map<Locale, String> descriptionMap, String xsd,
1498                            ServiceContext serviceContext, DDMStructure structure)
1499                    throws PortalException, SystemException {
1500    
1501                    try {
1502                            xsd = DDMXMLUtil.validateXML(xsd);
1503                            xsd = DDMXMLUtil.formatXML(xsd);
1504                    }
1505                    catch (Exception e) {
1506                            throw new StructureXsdException();
1507                    }
1508    
1509                    String parentXsd = StringPool.BLANK;
1510    
1511                    DDMStructure parentStructure =
1512                            ddmStructurePersistence.fetchByPrimaryKey(parentStructureId);
1513    
1514                    if (parentStructure != null) {
1515                            parentXsd = parentStructure.getCompleteXsd();
1516                    }
1517    
1518                    validate(nameMap, parentXsd, xsd);
1519    
1520                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
1521                    structure.setParentStructureId(parentStructureId);
1522                    structure.setNameMap(nameMap);
1523                    structure.setDescriptionMap(descriptionMap);
1524                    structure.setXsd(xsd);
1525    
1526                    ddmStructurePersistence.update(structure);
1527    
1528                    syncStructureTemplatesFields(structure);
1529    
1530                    Indexer indexer = IndexerRegistryUtil.getIndexer(
1531                            structure.getClassName());
1532    
1533                    if (indexer != null) {
1534                            List<Long> ddmStructureIds = getChildrenStructureIds(
1535                                    structure.getGroupId(), structure.getStructureId());
1536    
1537                            indexer.reindexDDMStructures(ddmStructureIds);
1538                    }
1539    
1540                    return structure;
1541            }
1542    
1543            protected void getChildrenStructureIds(
1544                            List<Long> structureIds, long groupId, long parentStructureId)
1545                    throws PortalException, SystemException {
1546    
1547                    List<DDMStructure> structures = ddmStructurePersistence.findByG_P(
1548                            groupId, parentStructureId);
1549    
1550                    for (DDMStructure structure : structures) {
1551                            structureIds.add(structure.getStructureId());
1552    
1553                            getChildrenStructureIds(
1554                                    structureIds, structure.getGroupId(),
1555                                    structure.getStructureId());
1556                    }
1557            }
1558    
1559            protected List<Long> getChildrenStructureIds(long groupId, long structureId)
1560                    throws PortalException, SystemException {
1561    
1562                    List<Long> structureIds = new ArrayList<Long>();
1563    
1564                    getChildrenStructureIds(structureIds, groupId, structureId);
1565    
1566                    structureIds.add(0, structureId);
1567    
1568                    return structureIds;
1569            }
1570    
1571            protected Set<String> getElementNames(Document document)
1572                    throws PortalException {
1573    
1574                    Set<String> elementNames = new HashSet<String>();
1575    
1576                    XPath xPathSelector = SAXReaderUtil.createXPath("//dynamic-element");
1577    
1578                    List<Node> nodes = xPathSelector.selectNodes(document);
1579    
1580                    for (Node node : nodes) {
1581                            Element element = (Element)node;
1582    
1583                            String name = StringUtil.toLowerCase(
1584                                    element.attributeValue("name"));
1585    
1586                            elementNames.add(name);
1587                    }
1588    
1589                    return elementNames;
1590            }
1591    
1592            protected String getStructureKey(String structureKey) {
1593                    if (structureKey != null) {
1594                            structureKey = structureKey.trim();
1595    
1596                            return StringUtil.toUpperCase(structureKey);
1597                    }
1598    
1599                    return StringPool.BLANK;
1600            }
1601    
1602            protected void syncStructureTemplatesFields(DDMStructure structure)
1603                    throws PortalException, SystemException {
1604    
1605                    long classNameId = PortalUtil.getClassNameId(DDMStructure.class);
1606    
1607                    List<DDMTemplate> templates = ddmTemplateLocalService.getTemplates(
1608                            structure.getGroupId(), classNameId, structure.getStructureId(),
1609                            DDMTemplateConstants.TEMPLATE_TYPE_FORM);
1610    
1611                    for (DDMTemplate template : templates) {
1612                            String script = template.getScript();
1613    
1614                            Document templateDocument = null;
1615    
1616                            try {
1617                                    templateDocument = SAXReaderUtil.read(script);
1618                            }
1619                            catch (DocumentException de) {
1620                                    if (_log.isWarnEnabled()) {
1621                                            _log.warn(de, de);
1622                                    }
1623    
1624                                    continue;
1625                            }
1626    
1627                            Element templateRootElement = templateDocument.getRootElement();
1628    
1629                            syncStructureTemplatesFields(template, templateRootElement);
1630    
1631                            appendNewStructureRequiredFields(structure, templateDocument);
1632    
1633                            try {
1634                                    script = DDMXMLUtil.formatXML(templateDocument.asXML());
1635                            }
1636                            catch (Exception e) {
1637                                    throw new StructureXsdException();
1638                            }
1639    
1640                            template.setScript(script);
1641    
1642                            ddmTemplatePersistence.update(template);
1643                    }
1644            }
1645    
1646            protected void syncStructureTemplatesFields(
1647                            DDMTemplate template, Element templateElement)
1648                    throws PortalException, SystemException {
1649    
1650                    DDMStructure structure = DDMTemplateHelperUtil.fetchStructure(template);
1651    
1652                    List<Element> dynamicElementElements = templateElement.elements(
1653                            "dynamic-element");
1654    
1655                    for (Element dynamicElementElement : dynamicElementElements) {
1656                            String dataType = dynamicElementElement.attributeValue("dataType");
1657                            String fieldName = dynamicElementElement.attributeValue("name");
1658    
1659                            if (Validator.isNull(dataType)) {
1660                                    continue;
1661                            }
1662    
1663                            if (!structure.hasField(fieldName)) {
1664                                    templateElement.remove(dynamicElementElement);
1665    
1666                                    continue;
1667                            }
1668    
1669                            String mode = template.getMode();
1670    
1671                            if (mode.equals(DDMTemplateConstants.TEMPLATE_MODE_CREATE)) {
1672                                    boolean fieldRequired = structure.getFieldRequired(fieldName);
1673    
1674                                    List<Element> metadataElements = dynamicElementElement.elements(
1675                                            "meta-data");
1676    
1677                                    for (Element metadataElement : metadataElements) {
1678                                            for (Element metadataEntryElement :
1679                                                            metadataElement.elements()) {
1680    
1681                                                    String attributeName =
1682                                                            metadataEntryElement.attributeValue("name");
1683    
1684                                                    if (fieldRequired && attributeName.equals("required")) {
1685                                                            metadataEntryElement.setText("true");
1686                                                    }
1687                                            }
1688                                    }
1689                            }
1690    
1691                            syncStructureTemplatesFields(template, dynamicElementElement);
1692                    }
1693            }
1694    
1695            protected void validate(Document document) throws PortalException {
1696                    XPath xPathSelector = SAXReaderUtil.createXPath("//dynamic-element");
1697    
1698                    List<Node> nodes = xPathSelector.selectNodes(document);
1699    
1700                    Set<String> elementNames = new HashSet<String>();
1701    
1702                    for (Node node : nodes) {
1703                            Element element = (Element)node;
1704    
1705                            String name = StringUtil.toLowerCase(
1706                                    element.attributeValue("name"));
1707    
1708                            if (name.startsWith(DDMStructureConstants.XSD_NAME_RESERVED)) {
1709                                    throw new StructureXsdException();
1710                            }
1711    
1712                            if (elementNames.contains(name)) {
1713                                    throw new StructureDuplicateElementException();
1714                            }
1715    
1716                            elementNames.add(name);
1717                    }
1718            }
1719    
1720            protected void validate(Document parentDocument, Document childDocument)
1721                    throws PortalException {
1722    
1723                    Set<String> parentElementNames = getElementNames(parentDocument);
1724    
1725                    for (String childElementName : getElementNames(childDocument)) {
1726                            if (parentElementNames.contains(childElementName)) {
1727                                    throw new StructureDuplicateElementException();
1728                            }
1729                    }
1730            }
1731    
1732            protected void validate(
1733                            long groupId, long parentStructureId, long classNameId,
1734                            String structureKey, Map<Locale, String> nameMap, String xsd)
1735                    throws PortalException, SystemException {
1736    
1737                    structureKey = getStructureKey(structureKey);
1738    
1739                    DDMStructure structure = ddmStructurePersistence.fetchByG_C_S(
1740                            groupId, classNameId, structureKey);
1741    
1742                    if (structure != null) {
1743                            StructureDuplicateStructureKeyException sdske =
1744                                    new StructureDuplicateStructureKeyException();
1745    
1746                            sdske.setStructureKey(structure.getStructureKey());
1747    
1748                            throw sdske;
1749                    }
1750    
1751                    String parentXsd = StringPool.BLANK;
1752    
1753                    DDMStructure parentStructure =
1754                            ddmStructurePersistence.fetchByPrimaryKey(parentStructureId);
1755    
1756                    if (parentStructure != null) {
1757                            parentXsd = parentStructure.getCompleteXsd();
1758                    }
1759    
1760                    validate(nameMap, parentXsd, xsd);
1761            }
1762    
1763            protected void validate(
1764                            Map<Locale, String> nameMap, Locale contentDefaultLocale)
1765                    throws PortalException {
1766    
1767                    String name = nameMap.get(contentDefaultLocale);
1768    
1769                    if (Validator.isNull(name)) {
1770                            throw new StructureNameException();
1771                    }
1772    
1773                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
1774    
1775                    if (!ArrayUtil.contains(availableLocales, contentDefaultLocale)) {
1776                            Long companyId = CompanyThreadLocal.getCompanyId();
1777    
1778                            LocaleException le = new LocaleException(
1779                                    LocaleException.TYPE_CONTENT,
1780                                    "The locale " + contentDefaultLocale +
1781                                            " is not available in company " + companyId);
1782    
1783                            le.setSourceAvailableLocales(new Locale[] {contentDefaultLocale});
1784                            le.setTargetAvailableLocales(availableLocales);
1785    
1786                            throw le;
1787                    }
1788            }
1789    
1790            protected void validate(
1791                            Map<Locale, String> nameMap, String parentXsd, String childXsd)
1792                    throws PortalException {
1793    
1794                    try {
1795                            Document document = SAXReaderUtil.read(childXsd);
1796    
1797                            Element rootElement = document.getRootElement();
1798    
1799                            Locale contentDefaultLocale = LocaleUtil.fromLanguageId(
1800                                    rootElement.attributeValue("default-locale"));
1801    
1802                            validate(nameMap, contentDefaultLocale);
1803    
1804                            validate(document);
1805    
1806                            if (Validator.isNotNull(parentXsd)) {
1807                                    Document parentDocument = SAXReaderUtil.read(parentXsd);
1808    
1809                                    validate(parentDocument, document);
1810                            }
1811                    }
1812                    catch (LocaleException le) {
1813                            throw le;
1814                    }
1815                    catch (StructureDuplicateElementException sdee) {
1816                            throw sdee;
1817                    }
1818                    catch (StructureNameException sne) {
1819                            throw sne;
1820                    }
1821                    catch (StructureXsdException sxe) {
1822                            throw sxe;
1823                    }
1824                    catch (Exception e) {
1825                            throw new StructureXsdException();
1826                    }
1827            }
1828    
1829            private static Log _log = LogFactoryUtil.getLog(
1830                    DDMStructureLocalServiceImpl.class);
1831    
1832    }