001    /**
002     * Copyright (c) 2000-2012 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.journal.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.CharPool;
023    import com.liferay.portal.kernel.util.LocaleUtil;
024    import com.liferay.portal.kernel.util.OrderByComparator;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.SAXReaderUtil;
031    import com.liferay.portal.model.Group;
032    import com.liferay.portal.model.ResourceConstants;
033    import com.liferay.portal.model.User;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.util.PortalUtil;
036    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
037    import com.liferay.portlet.expando.model.ExpandoBridge;
038    import com.liferay.portlet.journal.DuplicateStructureElementException;
039    import com.liferay.portlet.journal.DuplicateStructureIdException;
040    import com.liferay.portlet.journal.NoSuchArticleException;
041    import com.liferay.portlet.journal.NoSuchStructureException;
042    import com.liferay.portlet.journal.RequiredStructureException;
043    import com.liferay.portlet.journal.StructureIdException;
044    import com.liferay.portlet.journal.StructureInheritanceException;
045    import com.liferay.portlet.journal.StructureNameException;
046    import com.liferay.portlet.journal.StructureXsdException;
047    import com.liferay.portlet.journal.model.JournalArticle;
048    import com.liferay.portlet.journal.model.JournalStructure;
049    import com.liferay.portlet.journal.model.JournalStructureConstants;
050    import com.liferay.portlet.journal.service.base.JournalStructureLocalServiceBaseImpl;
051    import com.liferay.portlet.journal.util.JournalUtil;
052    import com.liferay.portlet.journal.util.comparator.StructurePKComparator;
053    
054    import java.util.ArrayList;
055    import java.util.Date;
056    import java.util.HashSet;
057    import java.util.List;
058    import java.util.Locale;
059    import java.util.Map;
060    import java.util.Set;
061    
062    /**
063     * @author Brian Wing Shun Chan
064     * @author Raymond Augé
065     */
066    public class JournalStructureLocalServiceImpl
067            extends JournalStructureLocalServiceBaseImpl {
068    
069            public JournalStructure addStructure(
070                            long userId, long groupId, String structureId,
071                            boolean autoStructureId, String parentStructureId,
072                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
073                            String xsd, ServiceContext serviceContext)
074                    throws PortalException, SystemException {
075    
076                    // Structure
077    
078                    User user = userPersistence.findByPrimaryKey(userId);
079                    structureId = structureId.trim().toUpperCase();
080                    Date now = new Date();
081    
082                    try {
083                            xsd = JournalUtil.validateXSD(xsd);
084                            xsd = DDMXMLUtil.formatXML(xsd);
085                    }
086                    catch (Exception e) {
087                            throw new StructureXsdException();
088                    }
089    
090                    if (autoStructureId) {
091                            structureId = String.valueOf(counterLocalService.increment());
092                    }
093    
094                    validate(
095                            groupId, structureId, autoStructureId, parentStructureId, nameMap,
096                            xsd);
097    
098                    long id = counterLocalService.increment();
099    
100                    JournalStructure structure = journalStructurePersistence.create(id);
101    
102                    structure.setUuid(serviceContext.getUuid());
103                    structure.setGroupId(groupId);
104                    structure.setCompanyId(user.getCompanyId());
105                    structure.setUserId(user.getUserId());
106                    structure.setUserName(user.getFullName());
107                    structure.setCreateDate(serviceContext.getCreateDate(now));
108                    structure.setModifiedDate(serviceContext.getModifiedDate(now));
109                    structure.setStructureId(structureId);
110                    structure.setParentStructureId(parentStructureId);
111                    structure.setNameMap(nameMap);
112                    structure.setDescriptionMap(descriptionMap);
113                    structure.setXsd(xsd);
114    
115                    journalStructurePersistence.update(structure);
116    
117                    // Resources
118    
119                    if (serviceContext.isAddGroupPermissions() ||
120                            serviceContext.isAddGuestPermissions()) {
121    
122                            addStructureResources(
123                                    structure, serviceContext.isAddGroupPermissions(),
124                                    serviceContext.isAddGuestPermissions());
125                    }
126                    else {
127                            addStructureResources(
128                                    structure, serviceContext.getGroupPermissions(),
129                                    serviceContext.getGuestPermissions());
130                    }
131    
132                    // Expando
133    
134                    ExpandoBridge expandoBridge = structure.getExpandoBridge();
135    
136                    expandoBridge.setAttributes(serviceContext);
137    
138                    return structure;
139            }
140    
141            public void addStructureResources(
142                            JournalStructure structure, boolean addGroupPermissions,
143                            boolean addGuestPermissions)
144                    throws PortalException, SystemException {
145    
146                    resourceLocalService.addResources(
147                            structure.getCompanyId(), structure.getGroupId(),
148                            structure.getUserId(), JournalStructure.class.getName(),
149                            structure.getId(), false, addGroupPermissions, addGuestPermissions);
150            }
151    
152            public void addStructureResources(
153                            JournalStructure structure, String[] groupPermissions,
154                            String[] guestPermissions)
155                    throws PortalException, SystemException {
156    
157                    resourceLocalService.addModelResources(
158                            structure.getCompanyId(), structure.getGroupId(),
159                            structure.getUserId(), JournalStructure.class.getName(),
160                            structure.getId(), groupPermissions, guestPermissions);
161            }
162    
163            public void addStructureResources(
164                            long groupId, String structureId, boolean addGroupPermissions,
165                            boolean addGuestPermissions)
166                    throws PortalException, SystemException {
167    
168                    JournalStructure structure = journalStructurePersistence.findByG_S(
169                            groupId, structureId);
170    
171                    addStructureResources(
172                            structure, addGroupPermissions, addGuestPermissions);
173            }
174    
175            public void addStructureResources(
176                            long groupId, String structureId, String[] groupPermissions,
177                            String[] guestPermissions)
178                    throws PortalException, SystemException {
179    
180                    JournalStructure structure = journalStructurePersistence.findByG_S(
181                            groupId, structureId);
182    
183                    addStructureResources(structure, groupPermissions, guestPermissions);
184            }
185    
186            public void checkNewLine(long groupId, String structureId)
187                    throws PortalException, SystemException {
188    
189                    JournalStructure structure = journalStructurePersistence.findByG_S(
190                            groupId, structureId);
191    
192                    String xsd = structure.getXsd();
193    
194                    if ((xsd != null) && xsd.contains("\\n")) {
195                            xsd = StringUtil.replace(
196                                    xsd, new String[] {"\\n", "\\r"}, new String[] {"\n", "\r"});
197    
198                            structure.setXsd(xsd);
199    
200                            journalStructurePersistence.update(structure);
201                    }
202            }
203    
204            public JournalStructure copyStructure(
205                            long userId, long groupId, String oldStructureId,
206                            String newStructureId, boolean autoStructureId)
207                    throws PortalException, SystemException {
208    
209                    // Structure
210    
211                    User user = userPersistence.findByPrimaryKey(userId);
212                    oldStructureId = oldStructureId.trim().toUpperCase();
213                    newStructureId = newStructureId.trim().toUpperCase();
214                    Date now = new Date();
215    
216                    JournalStructure oldStructure = journalStructurePersistence.findByG_S(
217                            groupId, oldStructureId);
218    
219                    if (autoStructureId) {
220                            newStructureId = String.valueOf(counterLocalService.increment());
221                    }
222                    else {
223                            validateStructureId(newStructureId);
224    
225                            JournalStructure newStructure =
226                                    journalStructurePersistence.fetchByG_S(groupId, newStructureId);
227    
228                            if (newStructure != null) {
229                                    throw new DuplicateStructureIdException();
230                            }
231                    }
232    
233                    long id = counterLocalService.increment();
234    
235                    JournalStructure newStructure = journalStructurePersistence.create(id);
236    
237                    newStructure.setGroupId(groupId);
238                    newStructure.setCompanyId(user.getCompanyId());
239                    newStructure.setUserId(user.getUserId());
240                    newStructure.setUserName(user.getFullName());
241                    newStructure.setCreateDate(now);
242                    newStructure.setModifiedDate(now);
243                    newStructure.setStructureId(newStructureId);
244                    newStructure.setNameMap(oldStructure.getNameMap());
245                    newStructure.setDescriptionMap(oldStructure.getDescriptionMap());
246                    newStructure.setXsd(oldStructure.getXsd());
247    
248                    journalStructurePersistence.update(newStructure);
249    
250                    // Resources
251    
252                    addStructureResources(newStructure, true, true);
253    
254                    return newStructure;
255            }
256    
257            public void deleteStructure(JournalStructure structure)
258                    throws PortalException, SystemException {
259    
260                    Group companyGroup = groupLocalService.getCompanyGroup(
261                            structure.getCompanyId());
262    
263                    if (structure.getGroupId() == companyGroup.getGroupId()) {
264                            if (journalArticlePersistence.countByStructureId(
265                                            structure.getStructureId()) > 0) {
266    
267                                    throw new RequiredStructureException(
268                                            RequiredStructureException.REFERENCED_WEB_CONTENT);
269                            }
270    
271                            if (journalStructurePersistence.countByParentStructureId(
272                                            structure.getStructureId()) > 0) {
273    
274                                    throw new RequiredStructureException(
275                                            RequiredStructureException.REFERENCED_STRUCTURE);
276                            }
277    
278                            if (journalTemplatePersistence.countByStructureId(
279                                            structure.getStructureId()) > 0) {
280    
281                                    throw new RequiredStructureException(
282                                            RequiredStructureException.REFERENCED_TEMPLATE);
283                            }
284                    }
285                    else {
286                            if (journalArticlePersistence.countByG_C_S(
287                                            structure.getGroupId(), 0,
288                                            structure.getStructureId()) > 0) {
289    
290                                    throw new RequiredStructureException(
291                                            RequiredStructureException.REFERENCED_WEB_CONTENT);
292                            }
293    
294                            if (journalStructurePersistence.countByG_P(
295                                            structure.getGroupId(), structure.getStructureId()) > 0) {
296    
297                                    throw new RequiredStructureException(
298                                            RequiredStructureException.REFERENCED_STRUCTURE);
299                            }
300    
301                            if (journalTemplatePersistence.countByG_S(
302                                            structure.getGroupId(), structure.getStructureId()) > 0) {
303    
304                                    throw new RequiredStructureException(
305                                            RequiredStructureException.REFERENCED_TEMPLATE);
306                            }
307                    }
308    
309                    // WebDAVProps
310    
311                    webDAVPropsLocalService.deleteWebDAVProps(
312                            JournalStructure.class.getName(), structure.getId());
313    
314                    // Expando
315    
316                    expandoValueLocalService.deleteValues(
317                            JournalStructure.class.getName(), structure.getId());
318    
319                    // Resources
320    
321                    resourceLocalService.deleteResource(
322                            structure.getCompanyId(), JournalStructure.class.getName(),
323                            ResourceConstants.SCOPE_INDIVIDUAL, structure.getId());
324    
325                    // Article
326    
327                    try {
328                            long classNameId = PortalUtil.getClassNameId(
329                                    JournalStructure.class.getName());
330    
331                            List<JournalArticle> articles =
332                                    journalArticlePersistence.findByG_C_C(
333                                            structure.getGroupId(), classNameId, structure.getId());
334    
335                            for (JournalArticle article : articles) {
336                                    journalArticleLocalService.deleteArticle(article, null, null);
337                            }
338                    }
339                    catch (NoSuchArticleException nsae) {
340                    }
341    
342                    // Structure
343    
344                    journalStructurePersistence.remove(structure);
345            }
346    
347            public void deleteStructure(long groupId, String structureId)
348                    throws PortalException, SystemException {
349    
350                    structureId = structureId.trim().toUpperCase();
351    
352                    JournalStructure structure = journalStructurePersistence.findByG_S(
353                            groupId, structureId);
354    
355                    deleteStructure(structure);
356            }
357    
358            public void deleteStructures(long groupId)
359                    throws PortalException, SystemException {
360    
361                    List<JournalStructure> structures =
362                            journalStructurePersistence.findByGroupId(
363                                    groupId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
364                                    new StructurePKComparator());
365    
366                    for (JournalStructure structure : structures) {
367                            deleteStructure(structure);
368                    }
369            }
370    
371            public JournalStructure getStructure(long id)
372                    throws PortalException, SystemException {
373    
374                    return journalStructurePersistence.findByPrimaryKey(id);
375            }
376    
377            public JournalStructure getStructure(long groupId, String structureId)
378                    throws PortalException, SystemException {
379    
380                    return getStructure(groupId, structureId, false);
381            }
382    
383            public JournalStructure getStructure(
384                            long groupId, String structureId, boolean includeGlobalStructures)
385                    throws PortalException, SystemException {
386    
387                    structureId = structureId.trim().toUpperCase();
388    
389                    if (groupId == 0) {
390                            _log.error(
391                                    "No group id was passed for " + structureId + ". Group id is " +
392                                            "required since 4.2.0. Please update all custom code and " +
393                                                    "data that references structures without a group id.");
394    
395                            List<JournalStructure> structures =
396                                    journalStructurePersistence.findByStructureId(structureId);
397    
398                            if (!structures.isEmpty()) {
399                                    return structures.get(0);
400                            }
401    
402                            throw new NoSuchStructureException(
403                                    "No JournalStructure exists with the structure id " +
404                                            structureId);
405                    }
406    
407                    JournalStructure structure = journalStructurePersistence.fetchByG_S(
408                            groupId, structureId);
409    
410                    if (structure != null) {
411                            return structure;
412                    }
413    
414                    if (!includeGlobalStructures) {
415                            throw new NoSuchStructureException(
416                                    "No JournalStructure exists with the structure id " +
417                                            structureId);
418                    }
419    
420                    Group group = groupPersistence.findByPrimaryKey(groupId);
421    
422                    Group companyGroup = groupLocalService.getCompanyGroup(
423                            group.getCompanyId());
424    
425                    return journalStructurePersistence.findByG_S(
426                            companyGroup.getGroupId(), structureId);
427            }
428    
429            public List<JournalStructure> getStructures() throws SystemException {
430                    return journalStructurePersistence.findAll();
431            }
432    
433            public List<JournalStructure> getStructures(long groupId)
434                    throws SystemException {
435    
436                    return journalStructurePersistence.findByGroupId(groupId);
437            }
438    
439            public List<JournalStructure> getStructures(
440                            long groupId, int start, int end)
441                    throws SystemException {
442    
443                    return journalStructurePersistence.findByGroupId(groupId, start, end);
444            }
445    
446            public int getStructuresCount(long groupId) throws SystemException {
447                    return journalStructurePersistence.countByGroupId(groupId);
448            }
449    
450            public List<JournalStructure> search(
451                            long companyId, long[] groupIds, String keywords, int start,
452                            int end, OrderByComparator obc)
453                    throws SystemException {
454    
455                    return journalStructureFinder.findByKeywords(
456                            companyId, groupIds, keywords, start, end, obc);
457            }
458    
459            public List<JournalStructure> search(
460                            long companyId, long[] groupIds, String structureId, String name,
461                            String description, boolean andOperator, int start, int end,
462                            OrderByComparator obc)
463                    throws SystemException {
464    
465                    return journalStructureFinder.findByC_G_S_N_D(
466                            companyId, groupIds, structureId, name, description, andOperator,
467                            start, end, obc);
468            }
469    
470            public int searchCount(long companyId, long[] groupIds, String keywords)
471                    throws SystemException {
472    
473                    return journalStructureFinder.countByKeywords(
474                            companyId, groupIds, keywords);
475            }
476    
477            public int searchCount(
478                            long companyId, long[] groupIds, String structureId, String name,
479                            String description, boolean andOperator)
480                    throws SystemException {
481    
482                    return journalStructureFinder.countByC_G_S_N_D(
483                            companyId, groupIds, structureId, name, description, andOperator);
484            }
485    
486            public JournalStructure updateStructure(
487                            long groupId, String structureId, String parentStructureId,
488                            Map<Locale, String> nameMap, Map<Locale, String> descriptionMap,
489                            String xsd, ServiceContext serviceContext)
490                    throws PortalException, SystemException {
491    
492                    structureId = structureId.trim().toUpperCase();
493    
494                    try {
495                            xsd = JournalUtil.validateXSD(xsd);
496                            xsd = DDMXMLUtil.formatXML(xsd);
497                    }
498                    catch (Exception e) {
499                            throw new StructureXsdException();
500                    }
501    
502                    validateParentStructureId(groupId, structureId, parentStructureId);
503                    validate(groupId, parentStructureId, nameMap, xsd);
504    
505                    JournalStructure structure = journalStructurePersistence.findByG_S(
506                            groupId, structureId);
507    
508                    structure.setModifiedDate(serviceContext.getModifiedDate(null));
509                    structure.setParentStructureId(parentStructureId);
510                    structure.setNameMap(nameMap);
511                    structure.setDescriptionMap(descriptionMap);
512                    structure.setXsd(xsd);
513    
514                    journalStructurePersistence.update(structure);
515    
516                    // Expando
517    
518                    ExpandoBridge expandoBridge = structure.getExpandoBridge();
519    
520                    expandoBridge.setAttributes(serviceContext);
521    
522                    return structure;
523            }
524    
525            protected void appendParentStructureElements(
526                            long groupId, String parentStructureId, List<Element> elements)
527                    throws Exception {
528    
529                    if (Validator.isNull(parentStructureId)) {
530                            return;
531                    }
532    
533                    JournalStructure parentStructure = getParentStructure(
534                            groupId, parentStructureId);
535    
536                    appendParentStructureElements(
537                            groupId, parentStructure.getParentStructureId(), elements);
538    
539                    Document document = SAXReaderUtil.read(parentStructure.getXsd());
540    
541                    Element rootElement = document.getRootElement();
542    
543                    elements.addAll(rootElement.elements());
544            }
545    
546            protected JournalStructure getParentStructure(
547                            long groupId, String parentStructureId)
548                    throws PortalException, SystemException {
549    
550                    JournalStructure parentStructure =
551                            journalStructurePersistence.fetchByG_S(groupId, parentStructureId);
552    
553                    if (parentStructure != null) {
554                            return parentStructure;
555                    }
556    
557                    Group group = groupPersistence.findByPrimaryKey(groupId);
558    
559                    Group companyGroup = groupLocalService.getCompanyGroup(
560                            group.getCompanyId());
561    
562                    if (groupId != companyGroup.getGroupId()) {
563                            parentStructure = journalStructurePersistence.findByG_S(
564                                    companyGroup.getGroupId(), parentStructureId);
565                    }
566    
567                    return parentStructure;
568            }
569    
570            protected void validate(List<Element> elements, Set<String> elNames)
571                    throws PortalException {
572    
573                    for (Element element : elements) {
574                            if (element.getName().equals("meta-data")) {
575                                    continue;
576                            }
577    
578                            String elName = element.attributeValue("name", StringPool.BLANK);
579                            String elType = element.attributeValue("type", StringPool.BLANK);
580    
581                            if (Validator.isNull(elName) ||
582                                    elName.startsWith(JournalStructureConstants.RESERVED)) {
583    
584                                    throw new StructureXsdException();
585                            }
586                            else {
587                                    String completePath = elName;
588    
589                                    Element parentElement = element.getParent();
590    
591                                    while (!parentElement.isRootElement()) {
592                                            completePath =
593                                                    parentElement.attributeValue("name", StringPool.BLANK) +
594                                                            StringPool.SLASH + completePath;
595    
596                                            parentElement = parentElement.getParent();
597                                    }
598    
599                                    String elNameLowerCase = completePath.toLowerCase();
600    
601                                    if (elNames.contains(elNameLowerCase)) {
602                                            throw new DuplicateStructureElementException();
603                                    }
604                                    else {
605                                            elNames.add(elNameLowerCase);
606                                    }
607                            }
608    
609                            if (Validator.isNull(elType)) {
610                                    throw new StructureXsdException();
611                            }
612    
613                            validate(element.elements(), elNames);
614                    }
615            }
616    
617            protected void validate(
618                            long groupId, String structureId, boolean autoStructureId,
619                            String parentStructureId, Map<Locale, String> nameMap, String xsd)
620                    throws PortalException, SystemException {
621    
622                    if (!autoStructureId) {
623                            validateStructureId(structureId);
624    
625                            JournalStructure structure = journalStructurePersistence.fetchByG_S(
626                                    groupId, structureId);
627    
628                            if (structure != null) {
629                                    throw new DuplicateStructureIdException();
630                            }
631                    }
632    
633                    validateParentStructureId(groupId, structureId, parentStructureId);
634                    validate(groupId, parentStructureId, nameMap, xsd);
635            }
636    
637            protected void validate(
638                            long groupId, String parentStructureId, Map<Locale, String> nameMap,
639                            String xsd)
640                    throws PortalException {
641    
642                    Locale locale = LocaleUtil.getDefault();
643    
644                    if (nameMap.isEmpty() || Validator.isNull(nameMap.get(locale))) {
645                            throw new StructureNameException();
646                    }
647    
648                    if (Validator.isNull(xsd)) {
649                            throw new StructureXsdException();
650                    }
651                    else {
652                            try {
653                                    List<Element> elements = new ArrayList<Element>();
654    
655                                    appendParentStructureElements(
656                                            groupId, parentStructureId, elements);
657    
658                                    Document document = SAXReaderUtil.read(xsd);
659    
660                                    Element rootElement = document.getRootElement();
661    
662                                    if (rootElement.elements().isEmpty()) {
663                                            throw new StructureXsdException();
664                                    }
665    
666                                    elements.addAll(rootElement.elements());
667    
668                                    Set<String> elNames = new HashSet<String>();
669    
670                                    validate(elements, elNames);
671                            }
672                            catch (DuplicateStructureElementException dsee) {
673                                    throw dsee;
674                            }
675                            catch (StructureXsdException sxe) {
676                                    throw sxe;
677                            }
678                            catch (Exception e) {
679                                    throw new StructureXsdException();
680                            }
681                    }
682            }
683    
684            protected void validateParentStructureId(
685                            long groupId, String structureId, String parentStructureId)
686                    throws PortalException, SystemException {
687    
688                    if (Validator.isNull(parentStructureId)) {
689                            return;
690                    }
691    
692                    if (parentStructureId.equals(structureId)) {
693                            throw new StructureInheritanceException();
694                    }
695    
696                    JournalStructure parentStructure = getParentStructure(
697                            groupId, parentStructureId);
698    
699                    while (parentStructure != null) {
700                            if ((parentStructure != null) &&
701                                    (parentStructure.getStructureId().equals(structureId) ||
702                                     parentStructure.getParentStructureId().equals(structureId))) {
703    
704                                    throw new StructureInheritanceException();
705                            }
706    
707                            try {
708                                    parentStructure = getParentStructure(
709                                            groupId, parentStructure.getParentStructureId());
710                            }
711                            catch (NoSuchStructureException nsse) {
712                                    break;
713                            }
714                    }
715            }
716    
717            protected void validateStructureId(String structureId)
718                    throws PortalException {
719    
720                    if (Validator.isNull(structureId) ||
721                            Validator.isNumber(structureId) ||
722                            (structureId.indexOf(CharPool.SPACE) != -1)) {
723    
724                            throw new StructureIdException();
725                    }
726            }
727    
728            private static Log _log = LogFactoryUtil.getLog(
729                    JournalStructureLocalServiceImpl.class);
730    
731    }