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.CharPool;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.GroupThreadLocal;
031    import com.liferay.portal.kernel.util.HtmlUtil;
032    import com.liferay.portal.kernel.util.LocaleUtil;
033    import com.liferay.portal.kernel.util.OrderByComparator;
034    import com.liferay.portal.kernel.util.StringPool;
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 = structureKey.trim().toUpperCase();
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, or <code>null</code> if no
893             *         matches could be found
894             * @throws SystemException if a system exception occurred
895             */
896            @Override
897            public List<DDMStructure> getStructures(long groupId, int start, int end)
898                    throws SystemException {
899    
900                    return ddmStructurePersistence.findByGroupId(groupId, start, end);
901            }
902    
903            /**
904             * Returns all the structures matching class name ID and group.
905             *
906             * @param  groupId the primary key of the group
907             * @param  classNameId the primary key of the class name for the structure's
908             *         related model
909             * @return the matching structures
910             * @throws SystemException if a system exception occurred
911             */
912            @Override
913            public List<DDMStructure> getStructures(long groupId, long classNameId)
914                    throws SystemException {
915    
916                    return ddmStructurePersistence.findByG_C(groupId, classNameId);
917            }
918    
919            /**
920             * Returns a range of all the structures that match the class name ID and
921             * group.
922             *
923             * <p>
924             * Useful when paginating results. Returns a maximum of <code>end -
925             * start</code> instances. <code>start</code> and <code>end</code> are not
926             * primary keys, they are indexes in the result set. Thus, <code>0</code>
927             * refers to the first result in the set. Setting both <code>start</code>
928             * and <code>end</code> to {@link
929             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
930             * result set.
931             * </p>
932             *
933             * @param  groupId the primary key of the group
934             * @param  classNameId the primary key of the class name for the structure's
935             *         related model
936             * @param  start the lower bound of the range of structures to return
937             * @param  end the upper bound of the range of structures to return (not
938             *         inclusive)
939             * @return the matching structures, or <code>null</code> if no matching
940             *         structures could be found
941             * @throws SystemException if a system exception occurred
942             */
943            @Override
944            public List<DDMStructure> getStructures(
945                            long groupId, long classNameId, int start, int end)
946                    throws SystemException {
947    
948                    return ddmStructurePersistence.findByG_C(
949                            groupId, classNameId, start, end);
950            }
951    
952            /**
953             * Returns an ordered range of all the structures matching the class name ID
954             * and group.
955             *
956             * <p>
957             * Useful when paginating results. Returns a maximum of <code>end -
958             * start</code> instances. <code>start</code> and <code>end</code> are not
959             * primary keys, they are indexes in the result set. Thus, <code>0</code>
960             * refers to the first result in the set. Setting both <code>start</code>
961             * and <code>end</code> to {@link
962             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
963             * result set.
964             * </p>
965             *
966             * @param  groupId the primary key of the group
967             * @param  classNameId the primary key of the class name for the structure's
968             *         related model
969             * @param  start the lower bound of the range of structures to return
970             * @param  end the upper bound of the range of structures to return (not
971             *         inclusive)
972             * @param  orderByComparator the comparator to order the structures
973             *         (optionally <code>null</code>)
974             * @return the range of matching structures ordered by the comparator
975             * @throws SystemException if a system exception occurred
976             */
977            @Override
978            public List<DDMStructure> getStructures(
979                            long groupId, long classNameId, int start, int end,
980                            OrderByComparator orderByComparator)
981                    throws SystemException {
982    
983                    return ddmStructurePersistence.findByG_C(
984                            groupId, classNameId, start, end, orderByComparator);
985            }
986    
987            @Override
988            public List<DDMStructure> getStructures(
989                            long groupId, String name, String description)
990                    throws SystemException {
991    
992                    return ddmStructurePersistence.findByG_N_D(groupId, name, description);
993            }
994    
995            /**
996             * Returns all the structures belonging to the groups.
997             *
998             * @param  groupIds the primary keys of the groups
999             * @return the structures belonging to the groups
1000             * @throws SystemException if a system exception occurred
1001             */
1002            @Override
1003            public List<DDMStructure> getStructures(long[] groupIds)
1004                    throws SystemException {
1005    
1006                    return ddmStructurePersistence.findByGroupId(groupIds);
1007            }
1008    
1009            /**
1010             * Returns all the structures matching the class name ID and belonging to
1011             * the groups.
1012             *
1013             * @param  groupIds the primary keys of the groups
1014             * @param  classNameId the primary key of the class name for the structure's
1015             *         related model
1016             * @return the structures matching the class name ID and belonging to the
1017             *         groups
1018             * @throws SystemException if a system exception occurred
1019             */
1020            @Override
1021            public List<DDMStructure> getStructures(long[] groupIds, long classNameId)
1022                    throws SystemException {
1023    
1024                    return ddmStructurePersistence.findByG_C(groupIds, classNameId);
1025            }
1026    
1027            @Override
1028            public List<DDMStructure> getStructures(
1029                            long[] groupIds, long classNameId, int start, int end)
1030                    throws SystemException {
1031    
1032                    return ddmStructurePersistence.findByG_C(
1033                            groupIds, classNameId, start, end);
1034            }
1035    
1036            /**
1037             * Returns the number of structures belonging to the group.
1038             *
1039             * @param  groupId the primary key of the group
1040             * @return the number of structures belonging to the group
1041             * @throws SystemException if a system exception occurred
1042             */
1043            @Override
1044            public int getStructuresCount(long groupId) throws SystemException {
1045                    return ddmStructurePersistence.countByGroupId(groupId);
1046            }
1047    
1048            /**
1049             * Returns the number of structures matching the class name ID and group.
1050             *
1051             * @param  groupId the primary key of the group
1052             * @param  classNameId the primary key of the class name for the structure's
1053             *         related model
1054             * @return the number of matching structures
1055             * @throws SystemException if a system exception occurred
1056             */
1057            @Override
1058            public int getStructuresCount(long groupId, long classNameId)
1059                    throws SystemException {
1060    
1061                    return ddmStructurePersistence.countByG_C(groupId, classNameId);
1062            }
1063    
1064            @Override
1065            public int getStructuresCount(long[] groupIds, long classNameId)
1066                    throws SystemException {
1067    
1068                    return ddmStructurePersistence.countByG_C(groupIds, classNameId);
1069            }
1070    
1071            /**
1072             * Returns an ordered range of all the structures matching the groups and
1073             * class name IDs, and matching the keywords in the structure names and
1074             * descriptions.
1075             *
1076             * <p>
1077             * Useful when paginating results. Returns a maximum of <code>end -
1078             * start</code> instances. <code>start</code> and <code>end</code> are not
1079             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1080             * refers to the first result in the set. Setting both <code>start</code>
1081             * and <code>end</code> to {@link
1082             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1083             * result set.
1084             * </p>
1085             *
1086             * @param  companyId the primary key of the structure's company
1087             * @param  groupIds the primary keys of the groups
1088             * @param  classNameIds the primary keys of the class names of the models
1089             *         the structures are related to
1090             * @param  keywords the keywords (space separated), which may occur in the
1091             *         structure's name or description (optionally <code>null</code>)
1092             * @param  start the lower bound of the range of structures to return
1093             * @param  end the upper bound of the range of structures to return (not
1094             *         inclusive)
1095             * @param  orderByComparator the comparator to order the structures
1096             *         (optionally <code>null</code>)
1097             * @return the range of matching structures ordered by the comparator
1098             * @throws SystemException if a system exception occurred
1099             */
1100            @Override
1101            public List<DDMStructure> search(
1102                            long companyId, long[] groupIds, long[] classNameIds,
1103                            String keywords, int start, int end,
1104                            OrderByComparator orderByComparator)
1105                    throws SystemException {
1106    
1107                    return ddmStructureFinder.findByKeywords(
1108                            companyId, groupIds, classNameIds, keywords, start, end,
1109                            orderByComparator);
1110            }
1111    
1112            /**
1113             * Returns an ordered range of all the structures matching the groups, class
1114             * name IDs, name keyword, description keyword, storage type, and type.
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  name the name keywords
1131             * @param  description the description keywords
1132             * @param  storageType the structure's storage type. It can be "xml" or
1133             *         "expando". For more information, see {@link
1134             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
1135             * @param  type the structure's type. For more information, see {@link
1136             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
1137             * @param  andOperator whether every field must match its keywords, or just
1138             *         one field
1139             * @param  start the lower bound of the range of structures to return
1140             * @param  end the upper bound of the range of structures to return (not
1141             *         inclusive)
1142             * @param  orderByComparator the comparator to order the structures
1143             *         (optionally <code>null</code>)
1144             * @return the range of matching structures ordered by the comparator
1145             * @throws SystemException if a system exception occurred
1146             */
1147            @Override
1148            public List<DDMStructure> search(
1149                            long companyId, long[] groupIds, long[] classNameIds, String name,
1150                            String description, String storageType, int type,
1151                            boolean andOperator, int start, int end,
1152                            OrderByComparator orderByComparator)
1153                    throws SystemException {
1154    
1155                    return ddmStructureFinder.findByC_G_C_N_D_S_T(
1156                            companyId, groupIds, classNameIds, name, description, storageType,
1157                            type, andOperator, start, end, orderByComparator);
1158            }
1159    
1160            /**
1161             * Returns the number of structures matching the groups and class name IDs,
1162             * and matching the keywords in the structure names and descriptions.
1163             *
1164             * @param  companyId the primary key of the structure's company
1165             * @param  groupIds the primary keys of the groups
1166             * @param  classNameIds the primary keys of the class names of the models
1167             *         the structures are related to
1168             * @param  keywords the keywords (space separated), which may occur in the
1169             *         structure's name or description (optionally <code>null</code>)
1170             * @return the number of matching structures
1171             * @throws SystemException if a system exception occurred
1172             */
1173            @Override
1174            public int searchCount(
1175                            long companyId, long[] groupIds, long[] classNameIds,
1176                            String keywords)
1177                    throws SystemException {
1178    
1179                    return ddmStructureFinder.countByKeywords(
1180                            companyId, groupIds, classNameIds, keywords);
1181            }
1182    
1183            /**
1184             * Returns the number of structures matching the groups, class name IDs,
1185             * name keyword, description keyword, storage type, and type
1186             *
1187             * @param  companyId the primary key of the structure's company
1188             * @param  groupIds the primary keys of the groups
1189             * @param  classNameIds the primary keys of the class names of the models
1190             *         the structure's are related to
1191             * @param  name the name keywords
1192             * @param  description the description keywords
1193             * @param  storageType the structure's storage type. It can be "xml" or
1194             *         "expando". For more information, see {@link
1195             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
1196             * @param  type the structure's type. For more information, see {@link
1197             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
1198             * @param  andOperator whether every field must match its keywords, or just
1199             *         one field
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, String name,
1206                            String description, String storageType, int type,
1207                            boolean andOperator)
1208                    throws SystemException {
1209    
1210                    return ddmStructureFinder.countByC_G_C_N_D_S_T(
1211                            companyId, groupIds, classNameIds, name, description, storageType,
1212                            type, andOperator);
1213            }
1214    
1215            /**
1216             * Updates the structure matching the class name ID, structure key, and
1217             * group, replacing its old parent structure, name map, description map, and
1218             * XSD with new ones.
1219             *
1220             * @param  groupId the primary key of the group
1221             * @param  parentStructureId the primary key of the new parent structure
1222             * @param  classNameId the primary key of the class name for the structure's
1223             *         related model
1224             * @param  structureKey the unique string identifying the structure
1225             * @param  nameMap the structure's new locales and localized names
1226             * @param  descriptionMap the structure's new locales and localized
1227             *         description
1228             * @param  xsd the structure's new XML schema definition
1229             * @param  serviceContext the service context to be applied. Can set the
1230             *         structure's modification date.
1231             * @return the updated structure
1232             * @throws PortalException if a matching structure could not be found, if
1233             *         the XSD was not well-formed, or if a portal exception occurred
1234             * @throws SystemException if a system exception occurred
1235             */
1236            @Override
1237            public DDMStructure updateStructure(
1238                            long groupId, long parentStructureId, long classNameId,
1239                            String structureKey, Map<Locale, String> nameMap,
1240                            Map<Locale, String> descriptionMap, String xsd,
1241                            ServiceContext serviceContext)
1242                    throws PortalException, SystemException {
1243    
1244                    structureKey = getStructureKey(structureKey);
1245    
1246                    DDMStructure structure = ddmStructurePersistence.findByG_C_S(
1247                            groupId, classNameId, structureKey);
1248    
1249                    return doUpdateStructure(
1250                            parentStructureId, nameMap, descriptionMap, xsd, serviceContext,
1251                            structure);
1252            }
1253    
1254            /**
1255             * Updates the structure matching the structure ID, replacing its old parent
1256             * structure, name map, description map, and XSD with new ones.
1257             *
1258             * @param  structureId the primary key of the structure
1259             * @param  parentStructureId the primary key of the new parent structure
1260             * @param  nameMap the structure's new locales and localized names
1261             * @param  descriptionMap the structure's new locales and localized
1262             *         descriptions
1263             * @param  xsd the structure's new XML schema definition
1264             * @param  serviceContext the service context to be applied. Can set the
1265             *         structure's modification date.
1266             * @return the updated structure
1267             * @throws PortalException if a matching structure could not be found, if
1268             *         the XSD was not well-formed, or if a portal exception occurred
1269             * @throws SystemException if a system exception occurred
1270             */
1271            @Override
1272            public DDMStructure updateStructure(
1273                            long structureId, long parentStructureId,
1274                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
1275                            String xsd, ServiceContext serviceContext)
1276                    throws PortalException, SystemException {
1277    
1278                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
1279                            structureId);
1280    
1281                    return doUpdateStructure(
1282                            parentStructureId, nameMap, descriptionMap, xsd, serviceContext,
1283                            structure);
1284            }
1285    
1286            /**
1287             * Updates the structure matching the structure ID, replacing its XSD with a
1288             * new one.
1289             *
1290             * @param  structureId the primary key of the structure
1291             * @param  xsd the structure's new XML schema definition
1292             * @param  serviceContext the service context to be applied. Can set the
1293             *         structure's modification date.
1294             * @return the updated structure
1295             * @throws PortalException if a matching structure could not be found, if
1296             *         the XSD was not well-formed, or if a portal exception occurred
1297             * @throws SystemException if a system exception occurred
1298             */
1299            @Override
1300            public DDMStructure updateXSD(
1301                            long structureId, String xsd, ServiceContext serviceContext)
1302                    throws PortalException, SystemException {
1303    
1304                    DDMStructure structure = ddmStructurePersistence.findByPrimaryKey(
1305                            structureId);
1306    
1307                    return doUpdateStructure(
1308                            structure.getParentStructureId(), structure.getNameMap(),
1309                            structure.getDescriptionMap(), xsd, serviceContext, structure);
1310            }
1311    
1312            /**
1313             * Updates the structure matching the structure ID, replacing the metadata
1314             * entry of the named field.
1315             *
1316             * @param  structureId the primary key of the structure
1317             * @param  fieldName the name of the field whose metadata to update
1318             * @param  metadataEntryName the metadata entry's name
1319             * @param  metadataEntryValue the metadata entry's value
1320             * @param  serviceContext the service context to be applied. Can set the
1321             *         structure's modification date.
1322             * @throws PortalException if a matching structure could not be found, if
1323             *         the XSD was not well-formed, or if a portal exception occurred
1324             * @throws SystemException if a system exception occurred
1325             */
1326            @Override
1327            public void updateXSDFieldMetadata(
1328                            long structureId, String fieldName, String metadataEntryName,
1329                            String metadataEntryValue, ServiceContext serviceContext)
1330                    throws PortalException, SystemException {
1331    
1332                    DDMStructure ddmStructure = fetchDDMStructure(structureId);
1333    
1334                    if (ddmStructure == null) {
1335                            return;
1336                    }
1337    
1338                    String xsd = ddmStructure.getXsd();
1339    
1340                    try {
1341                            Document document = SAXReaderUtil.read(xsd);
1342    
1343                            Element rootElement = document.getRootElement();
1344    
1345                            List<Element> dynamicElementElements = rootElement.elements(
1346                                    "dynamic-element");
1347    
1348                            for (Element dynamicElementElement : dynamicElementElements) {
1349                                    String dynamicElementElementFieldName = GetterUtil.getString(
1350                                            dynamicElementElement.attributeValue("name"));
1351    
1352                                    if (!dynamicElementElementFieldName.equals(fieldName)) {
1353                                            continue;
1354                                    }
1355    
1356                                    List<Element> metadataElements = dynamicElementElement.elements(
1357                                            "meta-data");
1358    
1359                                    for (Element metadataElement : metadataElements) {
1360                                            List<Element> metadataEntryElements =
1361                                                    metadataElement.elements();
1362    
1363                                            for (Element metadataEntryElement : metadataEntryElements) {
1364                                                    String metadataEntryElementName = GetterUtil.getString(
1365                                                            metadataEntryElement.attributeValue("name"));
1366    
1367                                                    if (metadataEntryElementName.equals(
1368                                                                    metadataEntryName)) {
1369    
1370                                                            metadataEntryElement.setText(metadataEntryValue);
1371                                                    }
1372                                            }
1373                                    }
1374                            }
1375    
1376                            updateXSD(structureId, document.asXML(), serviceContext);
1377                    }
1378                    catch (DocumentException de) {
1379                            throw new SystemException(de);
1380                    }
1381            }
1382    
1383            protected void appendNewStructureRequiredFields(
1384                    DDMStructure structure, Document templateDocument) {
1385    
1386                    String xsd = structure.getXsd();
1387    
1388                    Document structureDocument = null;
1389    
1390                    try {
1391                            structureDocument = SAXReaderUtil.read(xsd);
1392                    }
1393                    catch (DocumentException de) {
1394                            if (_log.isWarnEnabled()) {
1395                                    _log.warn(de, de);
1396                            }
1397    
1398                            return;
1399                    }
1400    
1401                    Element templateElement = templateDocument.getRootElement();
1402    
1403                    XPath structureXPath = SAXReaderUtil.createXPath(
1404                            "//dynamic-element[.//meta-data/entry[@name=\"required\"]=" +
1405                                    "\"true\"]");
1406    
1407                    List<Node> nodes = structureXPath.selectNodes(structureDocument);
1408    
1409                    for (Node node : nodes) {
1410                            Element element = (Element)node;
1411    
1412                            String name = element.attributeValue("name");
1413    
1414                            name = HtmlUtil.escapeXPathAttribute(name);
1415    
1416                            XPath templateXPath = SAXReaderUtil.createXPath(
1417                                    "//dynamic-element[@name=" + name + "]");
1418    
1419                            if (!templateXPath.booleanValueOf(templateDocument)) {
1420                                    templateElement.add(element.createCopy());
1421                            }
1422                    }
1423            }
1424    
1425            protected DDMStructure doUpdateStructure(
1426                            long parentStructureId, Map<Locale, String> nameMap,
1427                            Map<Locale, String> descriptionMap, String xsd,
1428                            ServiceContext serviceContext, DDMStructure structure)
1429                    throws PortalException, SystemException {
1430    
1431                    try {
1432                            xsd = DDMXMLUtil.validateXML(xsd);
1433                            xsd = DDMXMLUtil.formatXML(xsd);
1434                    }
1435                    catch (Exception e) {
1436                            throw new StructureXsdException();
1437                    }
1438    
1439                    validate(nameMap, xsd);
1440    
1441                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
1442                    structure.setParentStructureId(parentStructureId);
1443                    structure.setNameMap(nameMap);
1444                    structure.setDescriptionMap(descriptionMap);
1445                    structure.setXsd(xsd);
1446    
1447                    ddmStructurePersistence.update(structure);
1448    
1449                    syncStructureTemplatesFields(structure);
1450    
1451                    Indexer indexer = IndexerRegistryUtil.getIndexer(
1452                            structure.getClassName());
1453    
1454                    if (indexer != null) {
1455                            List<Long> ddmStructureIds = getChildrenStructureIds(
1456                                    structure.getGroupId(), structure.getStructureId());
1457    
1458                            indexer.reindexDDMStructures(ddmStructureIds);
1459                    }
1460    
1461                    return structure;
1462            }
1463    
1464            protected void getChildrenStructureIds(
1465                            List<Long> structureIds, long groupId, long structureId)
1466                    throws PortalException, SystemException {
1467    
1468                    List<DDMStructure> structures = ddmStructurePersistence.findByG_P(
1469                            groupId, structureId);
1470    
1471                    for (DDMStructure structure : structures) {
1472                            structureIds.add(structure.getStructureId());
1473    
1474                            getChildrenStructureIds(
1475                                    structureIds, structure.getGroupId(),
1476                                    structure.getParentStructureId());
1477                    }
1478            }
1479    
1480            protected List<Long> getChildrenStructureIds(long groupId, long structureId)
1481                    throws PortalException, SystemException {
1482    
1483                    List<Long> structureIds = new ArrayList<Long>();
1484    
1485                    getChildrenStructureIds(structureIds, groupId, structureId);
1486    
1487                    structureIds.add(0, structureId);
1488    
1489                    return structureIds;
1490            }
1491    
1492            protected String getStructureKey(String structureKey) {
1493                    if (structureKey != null) {
1494                            structureKey = structureKey.trim();
1495    
1496                            return structureKey.toUpperCase();
1497                    }
1498    
1499                    return StringPool.BLANK;
1500            }
1501    
1502            protected void syncStructureTemplatesFields(DDMStructure structure)
1503                    throws PortalException, SystemException {
1504    
1505                    long classNameId = PortalUtil.getClassNameId(DDMStructure.class);
1506    
1507                    List<DDMTemplate> templates = ddmTemplateLocalService.getTemplates(
1508                            structure.getGroupId(), classNameId, structure.getStructureId(),
1509                            DDMTemplateConstants.TEMPLATE_TYPE_FORM);
1510    
1511                    for (DDMTemplate template : templates) {
1512                            String script = template.getScript();
1513    
1514                            Document templateDocument = null;
1515    
1516                            try {
1517                                    templateDocument = SAXReaderUtil.read(script);
1518                            }
1519                            catch (DocumentException de) {
1520                                    if (_log.isWarnEnabled()) {
1521                                            _log.warn(de, de);
1522                                    }
1523    
1524                                    continue;
1525                            }
1526    
1527                            Element templateRootElement = templateDocument.getRootElement();
1528    
1529                            syncStructureTemplatesFields(template, templateRootElement);
1530    
1531                            appendNewStructureRequiredFields(structure, templateDocument);
1532    
1533                            try {
1534                                    script = DDMXMLUtil.formatXML(templateDocument.asXML());
1535                            }
1536                            catch (Exception e) {
1537                                    throw new StructureXsdException();
1538                            }
1539    
1540                            template.setScript(script);
1541    
1542                            ddmTemplatePersistence.update(template);
1543                    }
1544            }
1545    
1546            protected void syncStructureTemplatesFields(
1547                            DDMTemplate template, Element templateElement)
1548                    throws PortalException, SystemException {
1549    
1550                    DDMStructure structure = DDMTemplateHelperUtil.fetchStructure(template);
1551    
1552                    List<Element> dynamicElementElements = templateElement.elements(
1553                            "dynamic-element");
1554    
1555                    for (Element dynamicElementElement : dynamicElementElements) {
1556                            String dataType = dynamicElementElement.attributeValue("dataType");
1557                            String fieldName = dynamicElementElement.attributeValue("name");
1558    
1559                            if (Validator.isNull(dataType)) {
1560                                    continue;
1561                            }
1562    
1563                            if (!structure.hasField(fieldName)) {
1564                                    templateElement.remove(dynamicElementElement);
1565    
1566                                    continue;
1567                            }
1568    
1569                            String mode = template.getMode();
1570    
1571                            if (mode.equals(DDMTemplateConstants.TEMPLATE_MODE_CREATE)) {
1572                                    boolean fieldRequired = structure.getFieldRequired(fieldName);
1573    
1574                                    List<Element> metadataElements = dynamicElementElement.elements(
1575                                            "meta-data");
1576    
1577                                    for (Element metadataElement : metadataElements) {
1578                                            for (Element metadataEntryElement :
1579                                                            metadataElement.elements()) {
1580    
1581                                                    String attributeName =
1582                                                            metadataEntryElement.attributeValue("name");
1583    
1584                                                    if (fieldRequired && attributeName.equals("required")) {
1585                                                            metadataEntryElement.setText("true");
1586                                                    }
1587                                            }
1588                                    }
1589                            }
1590    
1591                            syncStructureTemplatesFields(template, dynamicElementElement);
1592                    }
1593            }
1594    
1595            protected void validate(List<Element> elements, Set<String> names)
1596                    throws PortalException {
1597    
1598                    for (Element element : elements) {
1599                            String elementName = element.getName();
1600    
1601                            if (elementName.equals("meta-data")) {
1602                                    continue;
1603                            }
1604    
1605                            String name = element.attributeValue("name", StringPool.BLANK);
1606                            String type = element.attributeValue("type", StringPool.BLANK);
1607    
1608                            if (Validator.isNull(name) ||
1609                                    name.startsWith(DDMStructureConstants.XSD_NAME_RESERVED)) {
1610    
1611                                    throw new StructureXsdException();
1612                            }
1613    
1614                            char[] charArray = name.toCharArray();
1615    
1616                            for (int i = 0; i < charArray.length; i++) {
1617                                    if (!Character.isLetterOrDigit(charArray[i]) &&
1618                                            (charArray[i] != CharPool.DASH) &&
1619                                            (charArray[i] != CharPool.UNDERLINE)) {
1620    
1621                                            throw new StructureXsdException();
1622                                    }
1623                            }
1624    
1625                            String path = name;
1626    
1627                            Element parentElement = element.getParent();
1628    
1629                            while (!parentElement.isRootElement()) {
1630                                    path =
1631                                            parentElement.attributeValue("name", StringPool.BLANK) +
1632                                                    StringPool.SLASH + path;
1633    
1634                                    parentElement = parentElement.getParent();
1635                            }
1636    
1637                            path = path.toLowerCase();
1638    
1639                            if (names.contains(path)) {
1640                                    throw new StructureDuplicateElementException();
1641                            }
1642                            else {
1643                                    names.add(path);
1644                            }
1645    
1646                            if (Validator.isNull(type)) {
1647                                    throw new StructureXsdException();
1648                            }
1649    
1650                            validate(element.elements(), names);
1651                    }
1652            }
1653    
1654            protected void validate(
1655                            long groupId, long classNameId, String structureKey,
1656                            Map<Locale, String> nameMap, String xsd)
1657                    throws PortalException, SystemException {
1658    
1659                    structureKey = getStructureKey(structureKey);
1660    
1661                    DDMStructure structure = ddmStructurePersistence.fetchByG_C_S(
1662                            groupId, classNameId, structureKey);
1663    
1664                    if (structure != null) {
1665                            StructureDuplicateStructureKeyException sdske =
1666                                    new StructureDuplicateStructureKeyException();
1667    
1668                            sdske.setStructureKey(structure.getStructureKey());
1669    
1670                            throw sdske;
1671                    }
1672    
1673                    validate(nameMap, xsd);
1674            }
1675    
1676            protected void validate(Map<Locale, String> nameMap, String xsd)
1677                    throws PortalException {
1678    
1679                    if (Validator.isNull(xsd)) {
1680                            throw new StructureXsdException();
1681                    }
1682                    else {
1683                            try {
1684                                    List<Element> elements = new ArrayList<Element>();
1685    
1686                                    Document document = SAXReaderUtil.read(xsd);
1687    
1688                                    Element rootElement = document.getRootElement();
1689    
1690                                    List<Element> rootElementElements = rootElement.elements();
1691    
1692                                    if (rootElementElements.isEmpty()) {
1693                                            throw new StructureXsdException();
1694                                    }
1695    
1696                                    Locale contentDefaultLocale = LocaleUtil.fromLanguageId(
1697                                            rootElement.attributeValue("default-locale"));
1698    
1699                                    validateLanguages(nameMap, contentDefaultLocale);
1700    
1701                                    elements.addAll(rootElement.elements());
1702    
1703                                    Set<String> elNames = new HashSet<String>();
1704    
1705                                    validate(elements, elNames);
1706                            }
1707                            catch (LocaleException le) {
1708                                    throw le;
1709                            }
1710                            catch (StructureDuplicateElementException sdee) {
1711                                    throw sdee;
1712                            }
1713                            catch (StructureNameException sne) {
1714                                    throw sne;
1715                            }
1716                            catch (StructureXsdException sxe) {
1717                                    throw sxe;
1718                            }
1719                            catch (Exception e) {
1720                                    throw new StructureXsdException();
1721                            }
1722                    }
1723            }
1724    
1725            protected void validateLanguages(
1726                            Map<Locale, String> nameMap, Locale contentDefaultLocale)
1727                    throws PortalException {
1728    
1729                    String name = nameMap.get(contentDefaultLocale);
1730    
1731                    if (Validator.isNull(name)) {
1732                            throw new StructureNameException();
1733                    }
1734    
1735                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
1736    
1737                    if (!ArrayUtil.contains(availableLocales, contentDefaultLocale)) {
1738                            Long companyId = CompanyThreadLocal.getCompanyId();
1739    
1740                            LocaleException le = new LocaleException(
1741                                    LocaleException.TYPE_CONTENT,
1742                                    "The locale " + contentDefaultLocale +
1743                                            " is not available in company " + companyId);
1744    
1745                            le.setSourceAvailableLocales(new Locale[] {contentDefaultLocale});
1746                            le.setTargetAvailableLocales(availableLocales);
1747    
1748                            throw le;
1749                    }
1750            }
1751    
1752            private static Log _log = LogFactoryUtil.getLog(
1753                    DDMStructureLocalServiceImpl.class);
1754    
1755    }