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