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