001    /**
002     * Copyright (c) 2000-present 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.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.util.ListUtil;
019    import com.liferay.portal.kernel.util.OrderByComparator;
020    import com.liferay.portal.security.permission.ActionKeys;
021    import com.liferay.portal.security.permission.PermissionChecker;
022    import com.liferay.portal.service.ServiceContext;
023    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
024    import com.liferay.portlet.dynamicdatamapping.service.base.DDMStructureServiceBaseImpl;
025    import com.liferay.portlet.dynamicdatamapping.service.permission.DDMPermission;
026    import com.liferay.portlet.dynamicdatamapping.service.permission.DDMStructurePermission;
027    import com.liferay.portlet.dynamicdatamapping.util.DDMDisplay;
028    import com.liferay.portlet.dynamicdatamapping.util.DDMUtil;
029    
030    import java.util.Iterator;
031    import java.util.List;
032    import java.util.Locale;
033    import java.util.Map;
034    
035    /**
036     * Provides the remote service for accessing, adding, deleting, and updating
037     * dynamic data mapping (DDM) structures. Its methods include permission checks.
038     *
039     * @author Brian Wing Shun Chan
040     * @author Bruno Basto
041     * @author Marcellus Tavares
042     * @see    com.liferay.portlet.dynamicdatamapping.service.impl.DDMStructureLocalServiceImpl
043     */
044    public class DDMStructureServiceImpl extends DDMStructureServiceBaseImpl {
045    
046            /**
047             * Adds a structure referencing a default parent structure, using the portal
048             * property <code>dynamic.data.lists.storage.type</code> storage type and
049             * default structure type.
050             *
051             * @param  userId the primary key of the structure's creator/owner
052             * @param  groupId the primary key of the group
053             * @param  classNameId the primary key of the class name for the structure's
054             *         related model
055             * @param  nameMap the structure's locales and localized names
056             * @param  descriptionMap the structure's locales and localized descriptions
057             * @param  xsd the structure's XML schema definition
058             * @param  serviceContext the service context to be applied. Can set the
059             *         UUID, creation date, modification date, guest permissions, and
060             *         group permissions for the structure.
061             * @return the structure
062             * @throws PortalException if a user with the primary key could not be
063             *         found, if the user did not have permission to add the structure,
064             *         if the XSD was not well-formed, or if a portal exception occurred
065             */
066            @Override
067            public DDMStructure addStructure(
068                            long userId, long groupId, long classNameId,
069                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
070                            String xsd, ServiceContext serviceContext)
071                    throws PortalException {
072    
073                    DDMDisplay ddmDisplay = DDMUtil.getDDMDisplay(serviceContext);
074    
075                    DDMPermission.check(
076                            getPermissionChecker(), serviceContext.getScopeGroupId(),
077                            ddmDisplay.getResourceName(), ddmDisplay.getAddStructureActionId());
078    
079                    return ddmStructureLocalService.addStructure(
080                            getUserId(), groupId, classNameId, nameMap, descriptionMap, xsd,
081                            serviceContext);
082            }
083    
084            /**
085             * Adds a structure referencing its parent structure.
086             *
087             * @param  groupId the primary key of the group
088             * @param  parentStructureId the primary key of the parent structure
089             *         (optionally {@link
090             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants#DEFAULT_PARENT_STRUCTURE_ID})
091             * @param  classNameId the primary key of the class name for the structure's
092             *         related model
093             * @param  structureKey the unique string identifying the structure
094             *         (optionally <code>null</code>)
095             * @param  nameMap the structure's locales and localized names
096             * @param  descriptionMap the structure's locales and localized descriptions
097             * @param  xsd the structure's XML schema definition
098             * @param  storageType the structure's storage type. It can be "xml" or
099             *         "expando". For more information, see {@link
100             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
101             * @param  type the structure's type. For more information, see {@link
102             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
103             * @param  serviceContext the service context to be applied. Can set the
104             *         UUID, creation date, modification date, guest permissions, and
105             *         group permissions for the structure.
106             * @return the structure
107             * @throws PortalException if the user did not have permission to add the
108             *         structure, if the XSD is not well formed, or if a portal
109             *         exception occurred
110             */
111            @Override
112            public DDMStructure addStructure(
113                            long groupId, long parentStructureId, long classNameId,
114                            String structureKey, Map<Locale, String> nameMap,
115                            Map<Locale, String> descriptionMap, String xsd, String storageType,
116                            int type, ServiceContext serviceContext)
117                    throws PortalException {
118    
119                    DDMDisplay ddmDisplay = DDMUtil.getDDMDisplay(serviceContext);
120    
121                    DDMPermission.check(
122                            getPermissionChecker(), serviceContext.getScopeGroupId(),
123                            ddmDisplay.getResourceName(), ddmDisplay.getAddStructureActionId());
124    
125                    return ddmStructureLocalService.addStructure(
126                            getUserId(), groupId, parentStructureId, classNameId, structureKey,
127                            nameMap, descriptionMap, xsd, storageType, type, serviceContext);
128            }
129    
130            /**
131             * Adds a structure referencing the parent structure by its structure key.
132             * In case the parent structure is not found, it uses the default parent
133             * structure ID.
134             *
135             * @param  userId the primary key of the structure's creator/owner
136             * @param  groupId the primary key of the group
137             * @param  parentStructureKey the unique string identifying the structure
138             * @param  classNameId the primary key of the class name for the structure's
139             *         related model
140             * @param  structureKey unique string identifying the structure (optionally
141             *         <code>null</code>)
142             * @param  nameMap the structure's locales and localized names
143             * @param  descriptionMap the structure's locales and localized descriptions
144             * @param  xsd the XML schema definition of the structure
145             * @param  storageType the storage type of the structure. It can be XML or
146             *         expando. For more information, see {@link
147             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
148             * @param  type the structure's type. For more information, see {@link
149             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
150             * @param  serviceContext the service context to be applied. Must have the
151             *         <code>ddmResource</code> attribute to check permissions. Can set
152             *         the UUID, creation date, modification date, guest permissions,
153             *         and group permissions for the structure.
154             * @return the structure
155             * @throws PortalException if a user with the primary key could not be
156             *         found, if the user did not have permission to add the structure,
157             *         if the XSD was not well-formed, or if a portal exception occurred
158             */
159            @Override
160            public DDMStructure addStructure(
161                            long userId, long groupId, String parentStructureKey,
162                            long classNameId, String structureKey, Map<Locale, String> nameMap,
163                            Map<Locale, String> descriptionMap, String xsd, String storageType,
164                            int type, ServiceContext serviceContext)
165                    throws PortalException {
166    
167                    DDMDisplay ddmDisplay = DDMUtil.getDDMDisplay(serviceContext);
168    
169                    DDMPermission.check(
170                            getPermissionChecker(), serviceContext.getScopeGroupId(),
171                            ddmDisplay.getResourceName(), ddmDisplay.getAddStructureActionId());
172    
173                    return ddmStructureLocalService.addStructure(
174                            userId, groupId, parentStructureKey, classNameId, structureKey,
175                            nameMap, descriptionMap, xsd, storageType, type, serviceContext);
176            }
177    
178            /**
179             * Copies a structure, creating a new structure with all the values
180             * extracted from the original one. The new structure supports a new name
181             * and description.
182             *
183             * @param  structureId the primary key of the structure to be copied
184             * @param  nameMap the new structure's locales and localized names
185             * @param  descriptionMap the new structure's locales and localized
186             *         descriptions
187             * @param  serviceContext the service context to be applied. Can set the
188             *         UUID, creation date, modification date, guest permissions, and
189             *         group permissions for the structure.
190             * @return the new structure
191             * @throws PortalException if the user did not have permission to add the
192             *         structure or if a portal exception occurred
193             */
194            @Override
195            public DDMStructure copyStructure(
196                            long structureId, Map<Locale, String> nameMap,
197                            Map<Locale, String> descriptionMap, ServiceContext serviceContext)
198                    throws PortalException {
199    
200                    DDMDisplay ddmDisplay = DDMUtil.getDDMDisplay(serviceContext);
201    
202                    DDMPermission.check(
203                            getPermissionChecker(), serviceContext.getScopeGroupId(),
204                            ddmDisplay.getResourceName(), ddmDisplay.getAddStructureActionId());
205    
206                    return ddmStructureLocalService.copyStructure(
207                            getUserId(), structureId, nameMap, descriptionMap, serviceContext);
208            }
209    
210            @Override
211            public DDMStructure copyStructure(
212                            long structureId, ServiceContext serviceContext)
213                    throws PortalException {
214    
215                    DDMDisplay ddmDisplay = DDMUtil.getDDMDisplay(serviceContext);
216    
217                    DDMPermission.check(
218                            getPermissionChecker(), serviceContext.getScopeGroupId(),
219                            ddmDisplay.getResourceName(), ddmDisplay.getAddStructureActionId());
220    
221                    return ddmStructureLocalService.copyStructure(
222                            getUserId(), structureId, serviceContext);
223            }
224    
225            /**
226             * Deletes the structure and its resources.
227             *
228             * <p>
229             * Before deleting the structure, the system verifies whether the structure
230             * is required by another entity. If it is needed, an exception is thrown.
231             * </p>
232             *
233             * @param  structureId the primary key of the structure to be deleted
234             * @throws PortalException if the user did not have permission to delete the
235             *         structure or if a portal exception occurred
236             */
237            @Override
238            public void deleteStructure(long structureId) throws PortalException {
239                    DDMStructurePermission.check(
240                            getPermissionChecker(), structureId, ActionKeys.DELETE);
241    
242                    ddmStructureLocalService.deleteStructure(structureId);
243            }
244    
245            /**
246             * Returns the structure matching the class name ID, structure key, and
247             * group.
248             *
249             * @param  groupId the primary key of the group
250             * @param  classNameId the primary key of the class name for the structure's
251             *         related model
252             * @param  structureKey the unique string identifying the structure
253             * @return the matching structure, or <code>null</code> if a matching
254             *         structure could not be found
255             * @throws PortalException if the user did not have permission to view the
256             *         structure or if a portal exception occurred
257             */
258            @Override
259            public DDMStructure fetchStructure(
260                            long groupId, long classNameId, String structureKey)
261                    throws PortalException {
262    
263                    DDMStructure ddmStructure = ddmStructurePersistence.fetchByG_C_S(
264                            groupId, classNameId, structureKey);
265    
266                    if (ddmStructure != null) {
267                            DDMStructurePermission.check(
268                                    getPermissionChecker(), ddmStructure, ActionKeys.VIEW);
269                    }
270    
271                    return ddmStructure;
272            }
273    
274            @Override
275            public List<DDMStructure> getJournalFolderStructures(
276                            long[] groupIds, long journalFolderId, int restrictionType)
277                    throws PortalException {
278    
279                    return filterStructures(
280                            ddmStructureLocalService.getJournalFolderStructures(
281                                    groupIds, journalFolderId, restrictionType));
282            }
283    
284            /**
285             * Returns the structure with the ID.
286             *
287             * @param  structureId the primary key of the structure
288             * @return the structure with the ID
289             * @throws PortalException if the user did not have permission to view the
290             *         structure or if a structure with the ID could not be found
291             */
292            @Override
293            public DDMStructure getStructure(long structureId) throws PortalException {
294                    DDMStructurePermission.check(
295                            getPermissionChecker(), structureId, ActionKeys.VIEW);
296    
297                    return ddmStructurePersistence.findByPrimaryKey(structureId);
298            }
299    
300            /**
301             * Returns the structure matching the class name ID, structure key, and
302             * group.
303             *
304             * @param  groupId the primary key of the structure's group
305             * @param  classNameId the primary key of the class name for the structure's
306             *         related model
307             * @param  structureKey the unique string identifying the structure
308             * @return the matching structure
309             * @throws PortalException if the user did not have permission to view the
310             *         structure or if a matching structure could not be found
311             */
312            @Override
313            public DDMStructure getStructure(
314                            long groupId, long classNameId, String structureKey)
315                    throws PortalException {
316    
317                    DDMStructurePermission.check(
318                            getPermissionChecker(), groupId, classNameId, structureKey,
319                            ActionKeys.VIEW);
320    
321                    return ddmStructureLocalService.getStructure(
322                            groupId, classNameId, structureKey);
323            }
324    
325            /**
326             * Returns the structure matching the class name ID, structure key, and
327             * group, optionally searching ancestor sites (that have sharing enabled)
328             * and global scoped sites.
329             *
330             * <p>
331             * This method first searches in the group. If the structure is still not
332             * found and <code>includeAncestorStructures</code> is set to
333             * <code>true</code>, this method searches the group's ancestor sites (that
334             * have sharing enabled) and lastly searches global scoped sites.
335             * </p>
336             *
337             * @param  groupId the primary key of the structure's group
338             * @param  classNameId the primary key of the class name for the structure's
339             *         related model
340             * @param  structureKey the unique string identifying the structure
341             * @param  includeAncestorStructures whether to include ancestor sites (that
342             *         have sharing enabled) and include global scoped sites in the
343             *         search
344             * @return the matching structure
345             * @throws PortalException if the user did not have permission to view the
346             *         structure or if a matching structure could not be found
347             */
348            @Override
349            public DDMStructure getStructure(
350                            long groupId, long classNameId, String structureKey,
351                            boolean includeAncestorStructures)
352                    throws PortalException {
353    
354                    DDMStructurePermission.check(
355                            getPermissionChecker(), groupId, classNameId, structureKey,
356                            ActionKeys.VIEW);
357    
358                    return ddmStructureLocalService.getStructure(
359                            groupId, classNameId, structureKey, includeAncestorStructures);
360            }
361    
362            /**
363             * Returns all the structures in the group that the user has permission to
364             * view.
365             *
366             * @param  groupId the primary key of the group
367             * @return the structures in the group that the user has permission to view
368             */
369            @Override
370            public List<DDMStructure> getStructures(long groupId) {
371                    return ddmStructurePersistence.filterFindByGroupId(groupId);
372            }
373    
374            /**
375             * Returns all the structures in the groups that the user has permission to
376             * view.
377             *
378             * @param  groupIds the primary key of the groups
379             * @return the structures in the groups that the user has permission to view
380             */
381            @Override
382            public List<DDMStructure> getStructures(long[] groupIds) {
383                    return ddmStructurePersistence.filterFindByGroupId(groupIds);
384            }
385    
386            /**
387             * Returns all the structures matching the groups and class name ID that the
388             * user has permission to view.
389             *
390             * @param  groupIds the primary keys of the groups
391             * @param  classNameId the primary key of the class name for the structure's
392             *         related model
393             * @return the structures matching the groups and class name ID that the
394             *         user has permission to view
395             */
396            @Override
397            public List<DDMStructure> getStructures(long[] groupIds, long classNameId) {
398                    return ddmStructurePersistence.filterFindByG_C(groupIds, classNameId);
399            }
400    
401            @Override
402            public List<DDMStructure> getStructures(
403                    long[] groupIds, long classNameId, int start, int end) {
404    
405                    return ddmStructurePersistence.filterFindByG_C(
406                            groupIds, classNameId, start, end);
407            }
408    
409            /**
410             * Returns an ordered range of all the structures matching the groups and
411             * class name IDs, and matching the keywords in the structure names and
412             * descriptions.
413             *
414             * <p>
415             * Useful when paginating results. Returns a maximum of <code>end -
416             * start</code> instances. <code>start</code> and <code>end</code> are not
417             * primary keys, they are indexes in the result set. Thus, <code>0</code>
418             * refers to the first result in the set. Setting both <code>start</code>
419             * and <code>end</code> to {@link
420             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
421             * result set.
422             * </p>
423             *
424             * @param  companyId the primary key of the structure's company
425             * @param  groupIds the primary keys of the groups
426             * @param  classNameIds the primary keys of the class names of the models
427             *         the structures are related to
428             * @param  keywords the keywords (space separated), which may occur in the
429             *         structure's name or description (optionally <code>null</code>)
430             * @param  start the lower bound of the range of structures to return
431             * @param  end the upper bound of the range of structures to return (not
432             *         inclusive)
433             * @param  orderByComparator the comparator to order the structures
434             *         (optionally <code>null</code>)
435             * @return the range of matching structures ordered by the comparator
436             */
437            @Override
438            public List<DDMStructure> search(
439                    long companyId, long[] groupIds, long[] classNameIds, String keywords,
440                    int start, int end, OrderByComparator<DDMStructure> orderByComparator) {
441    
442                    return ddmStructureFinder.filterFindByKeywords(
443                            companyId, groupIds, classNameIds, keywords, start, end,
444                            orderByComparator);
445            }
446    
447            /**
448             * Returns an ordered range of all the structures matching the groups, class
449             * name IDs, name keyword, description keyword, storage type, and type.
450             *
451             * <p>
452             * Useful when paginating results. Returns a maximum of <code>end -
453             * start</code> instances. <code>start</code> and <code>end</code> are not
454             * primary keys, they are indexes in the result set. Thus, <code>0</code>
455             * refers to the first result in the set. Setting both <code>start</code>
456             * and <code>end</code> to {@link
457             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
458             * result set.
459             * </p>
460             *
461             * @param  companyId the primary key of the structure's company
462             * @param  groupIds the primary keys of the groups
463             * @param  classNameIds the primary keys of the class names of the models
464             *         the structures are related to
465             * @param  name the name keywords
466             * @param  description the description keywords
467             * @param  storageType the structure's storage type. It can be "xml" or
468             *         "expando". For more information, see {@link
469             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
470             * @param  type the structure's type. For more information, see {@link
471             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
472             * @param  andOperator whether every field must match its keywords, or just
473             *         one field
474             * @param  start the lower bound of the range of structures to return
475             * @param  end the upper bound of the range of structures to return (not
476             *         inclusive)
477             * @param  orderByComparator the comparator to order the structures
478             *         (optionally <code>null</code>)
479             * @return the range of matching structures ordered by the comparator
480             */
481            @Override
482            public List<DDMStructure> search(
483                    long companyId, long[] groupIds, long[] classNameIds, String name,
484                    String description, String storageType, int type, boolean andOperator,
485                    int start, int end, OrderByComparator<DDMStructure> orderByComparator) {
486    
487                    return ddmStructureFinder.filterFindByC_G_C_N_D_S_T(
488                            companyId, groupIds, classNameIds, name, description, storageType,
489                            type, andOperator, start, end, orderByComparator);
490            }
491    
492            /**
493             * Returns the number of structures matching the groups and class name IDs,
494             * and matching the keywords in the structure names and descriptions.
495             *
496             * @param  companyId the primary key of the structure's company
497             * @param  groupIds the primary keys of the groups
498             * @param  classNameIds the primary keys of the class names of the models
499             *         the structures are related to
500             * @param  keywords the keywords (space separated), which may occur in the
501             *         structure's name or description (optionally <code>null</code>)
502             * @return the number of matching structures
503             */
504            @Override
505            public int searchCount(
506                    long companyId, long[] groupIds, long[] classNameIds, String keywords) {
507    
508                    return ddmStructureFinder.filterCountByKeywords(
509                            companyId, groupIds, classNameIds, keywords);
510            }
511    
512            /**
513             * Returns the number of structures matching the groups, class name IDs,
514             * name keyword, description keyword, storage type, and type
515             *
516             * @param  companyId the primary key of the structure's company
517             * @param  groupIds the primary keys of the groups
518             * @param  classNameIds the primary keys of the class names of the models
519             *         the structure's are related to
520             * @param  name the name keywords
521             * @param  description the description keywords
522             * @param  storageType the structure's storage type. It can be "xml" or
523             *         "expando". For more information, see {@link
524             *         com.liferay.portlet.dynamicdatamapping.storage.StorageType}.
525             * @param  type the structure's type. For more information, see {@link
526             *         com.liferay.portlet.dynamicdatamapping.model.DDMStructureConstants}.
527             * @param  andOperator whether every field must match its keywords, or just
528             *         one field
529             * @return the number of matching structures
530             */
531            @Override
532            public int searchCount(
533                    long companyId, long[] groupIds, long[] classNameIds, String name,
534                    String description, String storageType, int type, boolean andOperator) {
535    
536                    return ddmStructureFinder.filterCountByC_G_C_N_D_S_T(
537                            companyId, groupIds, classNameIds, name, description, storageType,
538                            type, andOperator);
539            }
540    
541            /**
542             * Updates the structure matching the class name ID, structure key, and
543             * group, replacing its old parent structure, name map, description map, and
544             * XSD with new ones.
545             *
546             * @param  groupId the primary key of the group
547             * @param  parentStructureId the primary key of the new parent structure
548             * @param  classNameId the primary key of the class name for the structure's
549             *         related model
550             * @param  structureKey the unique string identifying the structure
551             * @param  nameMap the structure's new locales and localized names
552             * @param  descriptionMap the structure's new locales and localized
553             *         description
554             * @param  xsd the structure's new XML schema definition
555             * @param  serviceContext the service context to be applied. Can set the
556             *         modification date.
557             * @return the updated structure
558             * @throws PortalException if the user did not have permission to update the
559             *         structure or if a portal exception occurred
560             */
561            @Override
562            public DDMStructure updateStructure(
563                            long groupId, long parentStructureId, long classNameId,
564                            String structureKey, Map<Locale, String> nameMap,
565                            Map<Locale, String> descriptionMap, String xsd,
566                            ServiceContext serviceContext)
567                    throws PortalException {
568    
569                    DDMStructurePermission.check(
570                            getPermissionChecker(), groupId, classNameId, structureKey,
571                            ActionKeys.UPDATE);
572    
573                    return ddmStructureLocalService.updateStructure(
574                            groupId, parentStructureId, classNameId, structureKey, nameMap,
575                            descriptionMap, xsd, serviceContext);
576            }
577    
578            /**
579             * Updates the structure matching the structure ID, replacing the old parent
580             * structure ID, name map, description map, and XSD with the new values.
581             *
582             * @param  structureId the primary key of the structure
583             * @param  parentStructureId the new parent structure primary key
584             * @param  nameMap the structure's new locales and localized names
585             * @param  descriptionMap the structure's new locales and localized
586             *         description
587             * @param  xsd the new XML schema definition of the structure
588             * @param  serviceContext the service context to be applied. Can set the
589             *         modification date.
590             * @return the updated structure
591             * @throws PortalException if the user did not have permission to update the
592             *         structure or if a portal exception occurred
593             */
594            @Override
595            public DDMStructure updateStructure(
596                            long structureId, long parentStructureId,
597                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
598                            String xsd, ServiceContext serviceContext)
599                    throws PortalException {
600    
601                    DDMStructurePermission.check(
602                            getPermissionChecker(), structureId, ActionKeys.UPDATE);
603    
604                    return ddmStructureLocalService.updateStructure(
605                            structureId, parentStructureId, nameMap, descriptionMap, xsd,
606                            serviceContext);
607            }
608    
609            protected List<DDMStructure> filterStructures(List<DDMStructure> structures)
610                    throws PortalException {
611    
612                    PermissionChecker permissionChecker = getPermissionChecker();
613    
614                    structures = ListUtil.copy(structures);
615    
616                    Iterator<DDMStructure> itr = structures.iterator();
617    
618                    while (itr.hasNext()) {
619                            DDMStructure structure = itr.next();
620    
621                            if (!DDMStructurePermission.contains(
622                                            permissionChecker, structure, ActionKeys.VIEW)) {
623    
624                                    itr.remove();
625                            }
626                    }
627    
628                    return structures;
629            }
630    
631    }