001
014
015 package com.liferay.portal.service.impl;
016
017 import com.liferay.portal.exception.LayoutFriendlyURLException;
018 import com.liferay.portal.exception.LayoutFriendlyURLsException;
019 import com.liferay.portal.exception.LayoutNameException;
020 import com.liferay.portal.exception.LayoutParentLayoutIdException;
021 import com.liferay.portal.exception.LayoutTypeException;
022 import com.liferay.portal.exception.NoSuchLayoutException;
023 import com.liferay.portal.kernel.bean.BeanReference;
024 import com.liferay.portal.kernel.exception.PortalException;
025 import com.liferay.portal.kernel.language.LanguageUtil;
026 import com.liferay.portal.kernel.module.framework.service.IdentifiableOSGiService;
027 import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
028 import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
029 import com.liferay.portal.kernel.util.GetterUtil;
030 import com.liferay.portal.kernel.util.LocaleUtil;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.kernel.util.StringUtil;
033 import com.liferay.portal.kernel.util.Validator;
034 import com.liferay.portal.model.Group;
035 import com.liferay.portal.model.Layout;
036 import com.liferay.portal.model.LayoutConstants;
037 import com.liferay.portal.model.LayoutFriendlyURL;
038 import com.liferay.portal.model.LayoutSet;
039 import com.liferay.portal.model.LayoutSetPrototype;
040 import com.liferay.portal.model.LayoutType;
041 import com.liferay.portal.model.LayoutTypeController;
042 import com.liferay.portal.model.ResourceConstants;
043 import com.liferay.portal.model.Role;
044 import com.liferay.portal.model.RoleConstants;
045 import com.liferay.portal.model.impl.LayoutImpl;
046 import com.liferay.portal.security.permission.ActionKeys;
047 import com.liferay.portal.service.PortletLocalServiceUtil;
048 import com.liferay.portal.service.ResourcePermissionLocalService;
049 import com.liferay.portal.service.RoleLocalServiceUtil;
050 import com.liferay.portal.service.ServiceContext;
051 import com.liferay.portal.service.persistence.LayoutFriendlyURLPersistence;
052 import com.liferay.portal.service.persistence.LayoutPersistence;
053 import com.liferay.portal.service.persistence.LayoutSetPersistence;
054 import com.liferay.portal.util.LayoutTypeControllerTracker;
055 import com.liferay.portal.util.Portal;
056 import com.liferay.portal.util.PortalUtil;
057 import com.liferay.portal.util.comparator.LayoutPriorityComparator;
058 import com.liferay.sites.kernel.util.SitesUtil;
059
060 import java.util.HashMap;
061 import java.util.List;
062 import java.util.Locale;
063 import java.util.Map;
064
065
068 public class LayoutLocalServiceHelper implements IdentifiableOSGiService {
069
070 public String getFriendlyURL(
071 long groupId, boolean privateLayout, long layoutId, String name,
072 String friendlyURL)
073 throws PortalException {
074
075 friendlyURL = getFriendlyURL(friendlyURL);
076
077 if (Validator.isNotNull(friendlyURL)) {
078 return friendlyURL;
079 }
080
081 friendlyURL = StringPool.SLASH + getFriendlyURL(name);
082
083 String originalFriendlyURL = friendlyURL;
084
085 for (int i = 1;; i++) {
086 try {
087 validateFriendlyURL(
088 groupId, privateLayout, layoutId, friendlyURL);
089
090 break;
091 }
092 catch (LayoutFriendlyURLException lfurle) {
093 int type = lfurle.getType();
094
095 if (type == LayoutFriendlyURLException.DUPLICATE) {
096 friendlyURL = originalFriendlyURL + i;
097 }
098 else {
099 friendlyURL = StringPool.SLASH + layoutId;
100
101 break;
102 }
103 }
104 }
105
106 return friendlyURL;
107 }
108
109 public String getFriendlyURL(String friendlyURL) {
110 return FriendlyURLNormalizerUtil.normalize(friendlyURL);
111 }
112
113 public Map<Locale, String> getFriendlyURLMap(
114 long groupId, boolean privateLayout, long layoutId, String name,
115 Map<Locale, String> friendlyURLMap)
116 throws PortalException {
117
118 Map<Locale, String> newFriendlyURLMap = new HashMap<>();
119
120 for (Locale locale : LanguageUtil.getAvailableLocales(groupId)) {
121 String friendlyURL = friendlyURLMap.get(locale);
122
123 if (Validator.isNotNull(friendlyURL)) {
124 friendlyURL = getFriendlyURL(
125 groupId, privateLayout, layoutId, name, friendlyURL);
126
127 newFriendlyURLMap.put(locale, friendlyURL);
128 }
129 }
130
131 Locale siteDefaultLocale = LocaleUtil.getSiteDefault();
132
133 if (newFriendlyURLMap.isEmpty() ||
134 Validator.isNull(newFriendlyURLMap.get(siteDefaultLocale))) {
135
136 String friendlyURL = getFriendlyURL(
137 groupId, privateLayout, layoutId, name, StringPool.BLANK);
138
139 newFriendlyURLMap.put(siteDefaultLocale, friendlyURL);
140 }
141
142 return newFriendlyURLMap;
143 }
144
145 public int getNextPriority(
146 long groupId, boolean privateLayout, long parentLayoutId,
147 String sourcePrototypeLayoutUuid, int defaultPriority) {
148
149 try {
150 int priority = defaultPriority;
151
152 if (priority < 0) {
153 Layout layout = layoutPersistence.findByG_P_P_First(
154 groupId, privateLayout, parentLayoutId,
155 new LayoutPriorityComparator(false));
156
157 priority = layout.getPriority() + 1;
158 }
159
160 if ((priority < _PRIORITY_BUFFER) &&
161 Validator.isNull(sourcePrototypeLayoutUuid)) {
162
163 LayoutSet layoutSet = layoutSetPersistence.fetchByG_P(
164 groupId, privateLayout);
165
166 if (Validator.isNotNull(
167 layoutSet.getLayoutSetPrototypeUuid()) &&
168 layoutSet.isLayoutSetPrototypeLinkEnabled()) {
169
170 priority = priority + _PRIORITY_BUFFER;
171 }
172 }
173
174 return priority;
175 }
176 catch (NoSuchLayoutException nsle) {
177 return 0;
178 }
179 }
180
181 @Override
182 public String getOSGiServiceIdentifier() {
183 return LayoutLocalServiceHelper.class.getName();
184 }
185
186 public long getParentLayoutId(
187 long groupId, boolean privateLayout, long parentLayoutId) {
188
189 if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
190
191
192
193 Layout parentLayout = layoutPersistence.fetchByG_P_L(
194 groupId, privateLayout, parentLayoutId);
195
196 if (parentLayout == null) {
197 parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
198 }
199 }
200
201 return parentLayoutId;
202 }
203
204 public boolean hasLayoutSetPrototypeLayout(
205 LayoutSetPrototype layoutSetPrototype, String layoutUuid)
206 throws PortalException {
207
208 Layout layout = layoutPersistence.fetchByUUID_G_P(
209 layoutUuid, layoutSetPrototype.getGroupId(), true);
210
211 if (layout != null) {
212 return true;
213 }
214
215 return false;
216 }
217
218 public void validate(
219 long groupId, boolean privateLayout, long layoutId,
220 long parentLayoutId, String name, String type, boolean hidden,
221 Map<Locale, String> friendlyURLMap, ServiceContext serviceContext)
222 throws PortalException {
223
224 validateName(name);
225
226 boolean firstLayout = false;
227
228 if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
229 List<Layout> layouts = layoutPersistence.findByG_P_P(
230 groupId, privateLayout, parentLayoutId, 0, 1);
231
232 if (layouts.isEmpty()) {
233 firstLayout = true;
234 }
235 else {
236 long firstLayoutId = layouts.get(0).getLayoutId();
237
238 if (firstLayoutId == layoutId) {
239 firstLayout = true;
240 }
241 }
242 }
243 else {
244
245
246
247
248 Layout layout = layoutPersistence.fetchByG_P_L(
249 groupId, privateLayout, layoutId);
250 Layout parentLayout = layoutPersistence.findByG_P_L(
251 groupId, privateLayout, parentLayoutId);
252
253 if (((layout == null) ||
254 Validator.isNull(layout.getSourcePrototypeLayoutUuid())) &&
255 !SitesUtil.isLayoutSortable(parentLayout)) {
256
257 throw new LayoutParentLayoutIdException(
258 LayoutParentLayoutIdException.NOT_SORTABLE);
259 }
260 }
261
262 if (firstLayout) {
263 validateFirstLayout(type);
264 }
265
266 LayoutTypeController layoutTypeController =
267 LayoutTypeControllerTracker.getLayoutTypeController(type);
268
269 if (!layoutTypeController.isInstanceable()) {
270 boolean layoutInstanceableAllowed = GetterUtil.getBoolean(
271 serviceContext.getAttribute("layout.instanceable.allowed"));
272
273 if (!layoutInstanceableAllowed) {
274 throw new LayoutTypeException(
275 LayoutTypeException.NOT_INSTANCEABLE);
276 }
277 }
278
279 if (!layoutTypeController.isParentable()) {
280 if (layoutPersistence.countByG_P_P(
281 groupId, privateLayout, layoutId) > 0) {
282
283 throw new LayoutTypeException(
284 LayoutTypeException.NOT_PARENTABLE);
285 }
286 }
287
288 validateFriendlyURLs(groupId, privateLayout, layoutId, friendlyURLMap);
289 }
290
291 public void validateFirstLayout(Layout layout) throws PortalException {
292 Group group = layout.getGroup();
293
294 if (group.isGuest() && layout.isPublicLayout() &&
295 !hasGuestViewPermission(layout)) {
296
297 LayoutTypeException lte = new LayoutTypeException(
298 LayoutTypeException.FIRST_LAYOUT_PERMISSION);
299
300 throw lte;
301 }
302
303 validateFirstLayout(layout.getType());
304 }
305
306 public void validateFirstLayout(String type) throws PortalException {
307 LayoutTypeController layoutTypeController =
308 LayoutTypeControllerTracker.getLayoutTypeController(type);
309
310 if (Validator.isNull(type) || !layoutTypeController.isFirstPageable()) {
311 LayoutTypeException lte = new LayoutTypeException(
312 LayoutTypeException.FIRST_LAYOUT);
313
314 lte.setLayoutType(type);
315
316 throw lte;
317 }
318 }
319
320 public void validateFriendlyURL(
321 long groupId, boolean privateLayout, long layoutId,
322 String friendlyURL)
323 throws PortalException {
324
325 if (Validator.isNull(friendlyURL)) {
326 return;
327 }
328
329 int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
330
331 if (exceptionType != -1) {
332 throw new LayoutFriendlyURLException(exceptionType);
333 }
334
335 List<LayoutFriendlyURL> layoutFriendlyURLs =
336 layoutFriendlyURLPersistence.findByG_P_F(
337 groupId, privateLayout, friendlyURL);
338
339 for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
340 Layout layout = layoutPersistence.findByPrimaryKey(
341 layoutFriendlyURL.getPlid());
342
343 if (layout.getLayoutId() != layoutId) {
344 LayoutFriendlyURLException lfurle =
345 new LayoutFriendlyURLException(
346 LayoutFriendlyURLException.DUPLICATE);
347
348 lfurle.setDuplicateClassPK(layout.getPlid());
349 lfurle.setDuplicateClassName(Layout.class.getName());
350
351 throw lfurle;
352 }
353 }
354
355 LayoutImpl.validateFriendlyURLKeyword(friendlyURL);
356
357 if (friendlyURL.contains(Portal.FRIENDLY_URL_SEPARATOR)) {
358 LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
359 LayoutFriendlyURLException.KEYWORD_CONFLICT);
360
361 lfurle.setKeywordConflict(Portal.FRIENDLY_URL_SEPARATOR);
362
363 throw lfurle;
364 }
365
366 List<FriendlyURLMapper> friendlyURLMappers =
367 PortletLocalServiceUtil.getFriendlyURLMappers();
368
369 for (FriendlyURLMapper friendlyURLMapper : friendlyURLMappers) {
370 if (friendlyURLMapper.isCheckMappingWithPrefix()) {
371 continue;
372 }
373
374 String mapping = StringPool.SLASH + friendlyURLMapper.getMapping();
375
376 if (friendlyURL.contains(mapping + StringPool.SLASH) ||
377 friendlyURL.endsWith(mapping)) {
378
379 LayoutFriendlyURLException lfurle =
380 new LayoutFriendlyURLException(
381 LayoutFriendlyURLException.KEYWORD_CONFLICT);
382
383 lfurle.setKeywordConflict(friendlyURLMapper.getMapping());
384
385 throw lfurle;
386 }
387 }
388
389 for (Locale locale : LanguageUtil.getAvailableLocales()) {
390 String languageId = StringUtil.toLowerCase(
391 LocaleUtil.toLanguageId(locale));
392
393 String i18nPathLanguageId =
394 StringPool.SLASH +
395 PortalUtil.getI18nPathLanguageId(locale, languageId);
396
397 if (friendlyURL.startsWith(i18nPathLanguageId + StringPool.SLASH) ||
398 friendlyURL.startsWith(
399 StringPool.SLASH + languageId + StringPool.SLASH) ||
400 friendlyURL.endsWith(i18nPathLanguageId) ||
401 friendlyURL.endsWith(StringPool.SLASH + languageId)) {
402
403 LayoutFriendlyURLException lfurle =
404 new LayoutFriendlyURLException(
405 LayoutFriendlyURLException.KEYWORD_CONFLICT);
406
407 lfurle.setKeywordConflict(i18nPathLanguageId);
408
409 throw lfurle;
410 }
411 }
412
413 String layoutIdFriendlyURL = friendlyURL.substring(1);
414
415 if (Validator.isNumber(layoutIdFriendlyURL) &&
416 !layoutIdFriendlyURL.equals(String.valueOf(layoutId))) {
417
418 LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
419 LayoutFriendlyURLException.POSSIBLE_DUPLICATE);
420
421 lfurle.setKeywordConflict(layoutIdFriendlyURL);
422
423 throw lfurle;
424 }
425 }
426
427 public void validateFriendlyURLs(
428 long groupId, boolean privateLayout, long layoutId,
429 Map<Locale, String> friendlyURLMap)
430 throws PortalException {
431
432 LayoutFriendlyURLsException layoutFriendlyURLsException = null;
433
434 for (Map.Entry<Locale, String> entry : friendlyURLMap.entrySet()) {
435 try {
436 String friendlyURL = entry.getValue();
437
438 validateFriendlyURL(
439 groupId, privateLayout, layoutId, friendlyURL);
440 }
441 catch (LayoutFriendlyURLException lfurle) {
442 Locale locale = entry.getKey();
443
444 if (layoutFriendlyURLsException == null) {
445 layoutFriendlyURLsException =
446 new LayoutFriendlyURLsException(lfurle);
447 }
448 else {
449 layoutFriendlyURLsException.addSuppressed(lfurle);
450 }
451
452 layoutFriendlyURLsException.addLocalizedException(
453 locale, lfurle);
454 }
455 }
456
457 if (layoutFriendlyURLsException != null) {
458 throw layoutFriendlyURLsException;
459 }
460 }
461
462 public void validateName(String name) throws PortalException {
463 if (Validator.isNull(name)) {
464 throw new LayoutNameException();
465 }
466 }
467
468 public void validateName(String name, String languageId)
469 throws PortalException {
470
471 String defaultLanguageId = LocaleUtil.toLanguageId(
472 LocaleUtil.getSiteDefault());
473
474 if (defaultLanguageId.equals(languageId)) {
475 validateName(name);
476 }
477 }
478
479 public void validateParentLayoutId(
480 long groupId, boolean privateLayout, long layoutId,
481 long parentLayoutId)
482 throws PortalException {
483
484 Layout layout = layoutPersistence.findByG_P_L(
485 groupId, privateLayout, layoutId);
486
487 if (parentLayoutId == layout.getParentLayoutId()) {
488 return;
489 }
490
491
492
493 if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
494 return;
495 }
496
497
498
499 Layout parentLayout = layoutPersistence.findByG_P_L(
500 groupId, privateLayout, parentLayoutId);
501
502 LayoutType parentLayoutType = parentLayout.getLayoutType();
503
504 if (!parentLayoutType.isParentable()) {
505 throw new LayoutParentLayoutIdException(
506 LayoutParentLayoutIdException.NOT_PARENTABLE);
507 }
508
509
510
511
512 if (Validator.isNull(layout.getSourcePrototypeLayoutUuid()) &&
513 !SitesUtil.isLayoutSortable(parentLayout)) {
514
515 throw new LayoutParentLayoutIdException(
516 LayoutParentLayoutIdException.NOT_SORTABLE);
517 }
518
519
520
521 if (PortalUtil.isLayoutDescendant(layout, parentLayoutId)) {
522 throw new LayoutParentLayoutIdException(
523 LayoutParentLayoutIdException.SELF_DESCENDANT);
524 }
525
526
527
528 if (layout.getParentLayoutId() ==
529 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
530
531 List<Layout> layouts = layoutPersistence.findByG_P_P(
532 groupId, privateLayout,
533 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
534
535
536
537
538 long firstLayoutId = layouts.get(0).getLayoutId();
539
540 if (firstLayoutId == layoutId) {
541 Layout secondLayout = layouts.get(1);
542
543 LayoutType layoutType = secondLayout.getLayoutType();
544
545 if (Validator.isNull(secondLayout.getType()) ||
546 !layoutType.isFirstPageable()) {
547
548 throw new LayoutParentLayoutIdException(
549 LayoutParentLayoutIdException.FIRST_LAYOUT_TYPE);
550 }
551 }
552 }
553 }
554
555 protected boolean hasGuestViewPermission(Layout layout)
556 throws PortalException {
557
558 Role role = RoleLocalServiceUtil.getRole(
559 layout.getCompanyId(), RoleConstants.GUEST);
560
561 return resourcePermissionLocalService.hasResourcePermission(
562 layout.getCompanyId(), Layout.class.getName(),
563 ResourceConstants.SCOPE_INDIVIDUAL,
564 String.valueOf(layout.getPlid()), role.getRoleId(),
565 ActionKeys.VIEW);
566 }
567
568 @BeanReference(type = LayoutFriendlyURLPersistence.class)
569 protected LayoutFriendlyURLPersistence layoutFriendlyURLPersistence;
570
571 @BeanReference(type = LayoutPersistence.class)
572 protected LayoutPersistence layoutPersistence;
573
574 @BeanReference(type = LayoutSetPersistence.class)
575 protected LayoutSetPersistence layoutSetPersistence;
576
577 @BeanReference(type = ResourcePermissionLocalService.class)
578 protected ResourcePermissionLocalService resourcePermissionLocalService;
579
580 private static final int _PRIORITY_BUFFER = 1000000;
581
582 }