diff --git a/build.properties b/build.properties index 2cb6109c2f8488..00d2f59ff53cdf 100644 --- a/build.properties +++ b/build.properties @@ -159,6 +159,7 @@ # apps/frontend-js,\ # apps/frontend-taglib,\ # apps/frontend-theme,\ + # apps/frontend-token,\ # apps/gogo-shell,\ # apps/headless,\ # apps/hello-velocity,\ diff --git a/modules/apps/frontend-theme/frontend-theme-classic/src/WEB-INF/token-definition.json b/modules/apps/frontend-theme/frontend-theme-classic/src/WEB-INF/token-definition.json new file mode 100644 index 00000000000000..ed0b61b5c18ffa --- /dev/null +++ b/modules/apps/frontend-theme/frontend-theme-classic/src/WEB-INF/token-definition.json @@ -0,0 +1,473 @@ +{ + "tokenCategories": [ + { + "label": "general", + "name": "general" + }, + { + "label": "colors", + "name": "colors" + }, + { + "label": "typography", + "name": "typography" + }, + { + "label": "spaces", + "name": "spaces" + } + ], + "tokenSets": [ + { + "label": "general", + "name": "general" + }, + { + "label": "utility", + "name": "utility" + }, + { + "label": "layout", + "name": "layout" + }, + { + "label": "buttons", + "name": "buttons" + }, + { + "label": "alerts", + "name": "alerts" + }, + { + "label": "cards", + "name": "cards" + }, + { + "label": "forms", + "name": "forms" + }, + { + "label": "nav", + "name": "nav" + }, + { + "label": "portlet", + "name": "portlet" + }, + { + "label": "tables", + "name": "tables" + }, + { + "label": "lists", + "name": "lists" + } + ], + "tokens": [ + { + "cssVariable": "white", + "editorType": "ColorPicker", + "label": "white", + "name": "whiteColor", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-100", + "editorType": "ColorPicker", + "label": "gray-100", + "name": "gray100Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-200", + "editorType": "ColorPicker", + "label": "gray-200", + "name": "gray200Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-300", + "editorType": "ColorPicker", + "label": "gray-300", + "name": "gray300Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-400", + "editorType": "ColorPicker", + "label": "gray-400", + "name": "gray400Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-500", + "editorType": "ColorPicker", + "label": "gray-500", + "name": "gray500Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-600", + "editorType": "ColorPicker", + "label": "gray-600", + "name": "gray600Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-700", + "editorType": "ColorPicker", + "label": "gray-700", + "name": "gray700Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-800", + "editorType": "ColorPicker", + "label": "gray-800", + "name": "gray800Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "gray-900", + "editorType": "ColorPicker", + "label": "gray-900", + "name": "gray900Color", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "black", + "editorType": "ColorPicker", + "label": "black", + "name": "blackColor", + "tokenCategoryName": "colors", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "primary", + "editorType": "ColorPicker", + "label": "primary", + "name": "primaryColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "secondary", + "editorType": "ColorPicker", + "label": "secondary", + "name": "secondaryColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "success", + "editorType": "ColorPicker", + "label": "success", + "name": "successColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "info", + "editorType": "ColorPicker", + "label": "info", + "name": "infoColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "warning", + "editorType": "ColorPicker", + "label": "warning", + "name": "warningColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "danger", + "editorType": "ColorPicker", + "label": "danger", + "name": "dangerColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "dark", + "editorType": "ColorPicker", + "label": "dark", + "name": "darkColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "light", + "editorType": "ColorPicker", + "label": "light", + "name": "lightColor", + "tokenCategoryName": "colors", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "spacer", + "label": "spacer", + "name": "spacer", + "tokenCategoryName": "spaces", + "tokenSetName": "layout", + "type": "Float" + }, + { + "cssVariable": "container-max", + "label": "container-max", + "name": "containerMax", + "tokenCategoryName": "spaces", + "tokenSetName": "layout", + "type": "Float" + }, + { + "cssVariable": "border-radius", + "label": "border-radius", + "name": "borderRadius", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "border-radius-sm", + "label": "border-radius-sm", + "name": "borderRadiusSm", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "border-radius-lg", + "label": "border-radius-lg", + "name": "borderRadiusLg", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "border-radius-circle", + "label": "border-radius-circle", + "name": "borderRadiusCircle", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "rounded-pill", + "label": "rounded-pill", + "name": "roundedPill", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "box-shadow", + "label": "box-shadow", + "name": "boxShadow", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "box-shadow-sm", + "label": "box-shadow-sm", + "name": "boxShadowSm", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "box-shadow-lg", + "label": "box-shadow-lg", + "name": "boxShadowLg", + "tokenCategoryName": "general", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "font-family-sans-serif", + "label": "font-family-sans-serif", + "name": "fontFamilySansSerif", + "tokenCategoryName": "typography", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "font-family-monospace", + "label": "font-family-monospace", + "name": "fontFamilyMonospace", + "tokenCategoryName": "typography", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "font-family-base", + "label": "font-family-base", + "name": "fontFamilyBase", + "tokenCategoryName": "typography", + "tokenSetName": "general", + "type": "String" + }, + { + "cssVariable": "font-size-sm", + "label": "font-size-sm", + "name": "fontSizeSm", + "tokenCategoryName": "typography", + "tokenSetName": "general", + "type": "Float" + }, + { + "cssVariable": "font-size-base", + "label": "font-size-base", + "name": "fontSizeBase", + "tokenCategoryName": "typography", + "tokenSetName": "general", + "type": "Float" + }, + { + "cssVariable": "font-size-lg", + "label": "font-size-lg", + "name": "fontSizeLg", + "tokenCategoryName": "typography", + "tokenSetName": "general", + "type": "Float" + }, + { + "cssVariable": "font-weight-lighter", + "label": "font-weight-lighter", + "name": "fontWeightLighter", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "font-weight-light", + "label": "font-weight-light", + "name": "fontWeightLight", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "font-weight-normal", + "label": "font-weight-normal", + "name": "fontWeightNormal", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "font-weight-bold", + "label": "font-weight-bold", + "name": "fontWeightBold", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "font-weight-bolder", + "label": "font-weight-bolder", + "name": "fontWeightBolder", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "String" + }, + { + "cssVariable": "h1-font-size", + "label": "h1-font-size", + "name": "h1FontSize", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "h2-font-size", + "label": "h2-font-size", + "name": "h2FontSize", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "h3-font-size", + "label": "h3-font-size", + "name": "h3FontSize", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "h4-font-size", + "label": "h4-font-size", + "name": "h4FontSize", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "h5-font-size", + "label": "h5-font-size", + "name": "h5FontSize", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "h6-font-size", + "label": "h6-font-size", + "name": "h6FontSize", + "tokenCategoryName": "typography", + "tokenSetName": "utility", + "type": "Float" + }, + { + "cssVariable": "body-bg", + "editorType": "ColorPicker", + "label": "body-bg", + "name": "bodyBgColor", + "tokenCategoryName": "colors", + "tokenSetName": "layout", + "type": "String" + }, + { + "cssVariable": "body-color", + "editorType": "ColorPicker", + "label": "body-color", + "name": "bodyColor", + "tokenCategoryName": "colors", + "tokenSetName": "layout", + "type": "String" + } + ] +} \ No newline at end of file diff --git a/modules/apps/frontend-token/app.bnd b/modules/apps/frontend-token/app.bnd new file mode 100644 index 00000000000000..2d55635f59c68f --- /dev/null +++ b/modules/apps/frontend-token/app.bnd @@ -0,0 +1,15 @@ +Liferay-Releng-App-Description: +Liferay-Releng-App-Title: ${liferay.releng.app.title.prefix} Frontend Token +Liferay-Releng-Bundle: true +Liferay-Releng-Category: Utility +Liferay-Releng-Demo-Url: +Liferay-Releng-Deprecated: false +Liferay-Releng-Fix-Delivery-Method: core +Liferay-Releng-Labs: false +Liferay-Releng-Marketplace: true +Liferay-Releng-Portal-Required: true +Liferay-Releng-Public: ${liferay.releng.public} +Liferay-Releng-Restart-Required: true +Liferay-Releng-Suite: foundation +Liferay-Releng-Support-Url: http://www.liferay.com +Liferay-Releng-Supported: ${liferay.releng.supported} \ No newline at end of file diff --git a/modules/apps/frontend-token/build.gradle b/modules/apps/frontend-token/build.gradle new file mode 100644 index 00000000000000..259a5569ce96f2 --- /dev/null +++ b/modules/apps/frontend-token/build.gradle @@ -0,0 +1 @@ +apply plugin: "com.liferay.app.defaults.plugin" \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-api/.lfrbuild-portal b/modules/apps/frontend-token/frontend-token-definition-api/.lfrbuild-portal new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/modules/apps/frontend-token/frontend-token-definition-api/bnd.bnd b/modules/apps/frontend-token/frontend-token-definition-api/bnd.bnd new file mode 100644 index 00000000000000..34385ec373c8ef --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-api/bnd.bnd @@ -0,0 +1,4 @@ +Bundle-Name: Liferay Frontend Token Definition API +Bundle-SymbolicName: com.liferay.frontend.token.definition.api +Bundle-Version: 1.0.0 +Export-Package: com.liferay.frontend.token.definition \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-api/build.gradle b/modules/apps/frontend-token/frontend-token-definition-api/build.gradle new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/modules/apps/frontend-token/frontend-token-definition-api/src/main/java/com/liferay/frontend/token/definition/TokenDefinition.java b/modules/apps/frontend-token/frontend-token-definition-api/src/main/java/com/liferay/frontend/token/definition/TokenDefinition.java new file mode 100644 index 00000000000000..33e40a3e956b35 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-api/src/main/java/com/liferay/frontend/token/definition/TokenDefinition.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.token.definition; + +/** + * @author Iván Zaera + */ +public interface TokenDefinition { + + public String getRawTokenDefinition(); + +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-api/src/main/java/com/liferay/frontend/token/definition/TokenDefinitionRegistry.java b/modules/apps/frontend-token/frontend-token-definition-api/src/main/java/com/liferay/frontend/token/definition/TokenDefinitionRegistry.java new file mode 100644 index 00000000000000..e56e31e3580779 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-api/src/main/java/com/liferay/frontend/token/definition/TokenDefinitionRegistry.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.token.definition; + +import java.util.Collection; + +/** + * @author Iván Zaera + */ +public interface TokenDefinitionRegistry { + + public Collection getTokenDefinitions(); + +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-api/src/main/resources/com/liferay/frontend/token/definition/packageinfo b/modules/apps/frontend-token/frontend-token-definition-api/src/main/resources/com/liferay/frontend/token/definition/packageinfo new file mode 100644 index 00000000000000..e2525561ab2e7b --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-api/src/main/resources/com/liferay/frontend/token/definition/packageinfo @@ -0,0 +1 @@ +version 1.0.0 \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-api/src/main/resources/com/liferay/frontend/token/definition/token-definition.schema.json b/modules/apps/frontend-token/frontend-token-definition-api/src/main/resources/com/liferay/frontend/token/definition/token-definition.schema.json new file mode 100644 index 00000000000000..36865056286a9b --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-api/src/main/resources/com/liferay/frontend/token/definition/token-definition.schema.json @@ -0,0 +1,164 @@ +{ + "$id": "http://example.com/root.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "definitions": { + "Token": { + "additionalProperties": false, + "properties": { + "editorType": { + "enum": [ + "ColorPicker" + ], + "title": "The Editor Type used to edit the Token", + "type": "string" + }, + "label": { + "title": "The Language Key of the Token Label", + "type": "string" + }, + "mappings": { + "items": { + "additionalProperties": false, + "not": { + "type": "null" + }, + "properties": { + "type": { + "title": "The Type of the Mapping", + "type": "string" + }, + "value": { + "title": "The Value of the Mapping for the Token", + "type": "string" + } + }, + "required": [ + "type", + "value" + ], + "type": "object" + }, + "title": "The Mappings of the Token", + "type": "array" + }, + "name": { + "title": "Name of the Token", + "type": "string" + }, + "tokenCategoryName": { + "title": "Name of the TokenCategory associated to the Token", + "type": "string" + }, + "tokenSetName": { + "title": "Name of the TokenSet associated to the Token", + "type": "string" + }, + "type": { + "enum": [ + "Boolean", + "Integer", + "Number", + "String" + ], + "title": "Type of the Token", + "type": "string" + }, + "validValues": { + "items": { + "additionalProperties": false, + "not": { + "type": "null" + }, + "properties": { + "label": { + "title": "The Language Key of the Valid Value", + "type": "string" + }, + "value": { + "title": "Value", + "type": "string" + } + }, + "required": [ + "value" + ], + "title": "Valid Value", + "type": "object" + }, + "minItems": 1, + "title": "Valid Values", + "type": "array" + } + }, + "required": [ + "mappings", + "name", + "type" + ], + "type": "object" + }, + "TokenCategory": { + "additionalProperties": false, + "properties": { + "label": { + "title": "The Language Key to obtain the label of the Token Category", + "type": "string" + }, + "name": { + "title": "Name of the Token Category", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "TokenSet": { + "additionalProperties": false, + "properties": { + "label": { + "title": "The Language Key to obtain the label of the Token Set", + "type": "string" + }, + "name": { + "title": "Name of the Token Set", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + } + }, + "properties": { + "tokenCategories": { + "items": { + "$ref": "#/definitions/TokenCategory" + }, + "title": "Tokens", + "type": "array" + }, + "tokenSets": { + "items": { + "$ref": "#/definitions/TokenSet" + }, + "title": "Tokens", + "type": "array" + }, + "tokens": { + "items": { + "$ref": "#/definitions/Token" + }, + "title": "Tokens", + "type": "array" + } + }, + "required": [ + "tokens" + ], + "title": "The Design Tokens Definition Schema", + "type": "object" +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/.lfrbuild-portal b/modules/apps/frontend-token/frontend-token-definition-impl/.lfrbuild-portal new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/bnd.bnd b/modules/apps/frontend-token/frontend-token-definition-impl/bnd.bnd new file mode 100644 index 00000000000000..74adb54be54f16 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-impl/bnd.bnd @@ -0,0 +1,3 @@ +Bundle-Name: Liferay Frontend Token Definition Implementation +Bundle-SymbolicName: com.liferay.frontend.token.definition.impl +Bundle-Version: 1.0.0 \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/build.gradle b/modules/apps/frontend-token/frontend-token-definition-impl/build.gradle new file mode 100644 index 00000000000000..1dfd5cdd60f679 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-impl/build.gradle @@ -0,0 +1,6 @@ +dependencies { + compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "default" + compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0" + compileOnly group: "org.osgi", name: "osgi.core", version: "6.0.0" + compileOnly project(":apps:frontend-token:frontend-token-definition-api") +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/src/main/java/com/liferay/frontend/token/definition/internal/TokenDefinitionImpl.java b/modules/apps/frontend-token/frontend-token-definition-impl/src/main/java/com/liferay/frontend/token/definition/internal/TokenDefinitionImpl.java new file mode 100644 index 00000000000000..c64846cced8459 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-impl/src/main/java/com/liferay/frontend/token/definition/internal/TokenDefinitionImpl.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.token.definition.internal; + +import com.liferay.frontend.token.definition.TokenDefinition; + +/** + * @author Iván Zaera + */ +public class TokenDefinitionImpl implements TokenDefinition { + + public TokenDefinitionImpl(String rawTokenDefinition) { + _rawTokenDefinition = rawTokenDefinition; + } + + @Override + public String getRawTokenDefinition() { + return _rawTokenDefinition; + } + + private final String _rawTokenDefinition; + +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/src/main/java/com/liferay/frontend/token/definition/internal/TokenDefinitionRegistryImpl.java b/modules/apps/frontend-token/frontend-token-definition-impl/src/main/java/com/liferay/frontend/token/definition/internal/TokenDefinitionRegistryImpl.java new file mode 100644 index 00000000000000..ad6204054d478f --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-impl/src/main/java/com/liferay/frontend/token/definition/internal/TokenDefinitionRegistryImpl.java @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.token.definition.internal; + +import com.liferay.frontend.token.definition.TokenDefinition; +import com.liferay.frontend.token.definition.TokenDefinitionRegistry; +import com.liferay.portal.kernel.util.LocaleUtil; +import com.liferay.portal.kernel.util.StringUtil; +import com.liferay.portal.kernel.util.Validator; + +import java.io.IOException; +import java.io.InputStream; + +import java.net.URL; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Dictionary; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.util.tracker.BundleTracker; +import org.osgi.util.tracker.BundleTrackerCustomizer; + +/** + * @author Iván Zaera + */ +@Component(service = TokenDefinitionRegistry.class) +public class TokenDefinitionRegistryImpl implements TokenDefinitionRegistry { + + @Override + public Collection getTokenDefinitions() { + Map> map = + bundleTracker.getTracked(); + + Collection> atomicReferences = + map.values(); + + Stream> stream = + atomicReferences.stream(); + + return stream.reduce( + new ArrayList<>(), + (tokenDefinitions, atomicReference) -> { + TokenDefinition tokenDefinition = atomicReference.get(); + + if (tokenDefinition != null) { + tokenDefinitions.add(tokenDefinition); + } + + return tokenDefinitions; + }, + (tokenDefinitions, tokenDefinitions2) -> { + ArrayList combinedTokenDefinitions = + new ArrayList<>(); + + combinedTokenDefinitions.addAll(tokenDefinitions); + + combinedTokenDefinitions.addAll(tokenDefinitions2); + + return combinedTokenDefinitions; + }); + } + + @Activate + protected void activate(BundleContext bundleContext) { + bundleTracker = new BundleTracker<>( + bundleContext, Bundle.ACTIVE, + new BundleTrackerCustomizer>() { + + @Override + public AtomicReference addingBundle( + Bundle bundle, BundleEvent bundleEvent) { + + return new AtomicReference<>(getTokenDefinition(bundle)); + } + + @Override + public void modifiedBundle( + Bundle bundle, BundleEvent bundleEvent, + AtomicReference atomicReference) { + + atomicReference.set(getTokenDefinition(bundle)); + } + + @Override + public void removedBundle( + Bundle bundle, BundleEvent bundleEvent, + AtomicReference atomicReference) { + + atomicReference.set(null); + } + + }); + } + + @Deactivate + protected void deactivate() { + bundleTracker.close(); + } + + protected TokenDefinition getTokenDefinition(Bundle bundle) { + String tokenDefinitionPath = getTokenDefinitionPath(bundle); + + URL url = bundle.getEntry(tokenDefinitionPath); + + if (url == null) { + return null; + } + + try (InputStream is = url.openStream()) { + return new TokenDefinitionImpl(StringUtil.read(is)); + } + catch (IOException ioException) { + throw new RuntimeException( + "Unable to read: " + tokenDefinitionPath, ioException); + } + } + + protected String getTokenDefinitionPath(Bundle bundle) { + Locale defaultLocale = LocaleUtil.getDefault(); + + Dictionary headers = bundle.getHeaders( + defaultLocale.toString()); + + String tokenDefinitionPath = headers.get("Token-Definition-Path"); + + if (Validator.isNull(tokenDefinitionPath)) { + tokenDefinitionPath = "META-INF/token-definition.json"; + } + + if (tokenDefinitionPath.charAt(0) == '/') { + tokenDefinitionPath = tokenDefinitionPath.substring(1); + } + + return tokenDefinitionPath; + } + + protected BundleTracker> bundleTracker; + +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/src/test/java/com/liferay/frontend/token/definition/internal/TokenDefinitionRegistryImplTest.java b/modules/apps/frontend-token/frontend-token-definition-impl/src/test/java/com/liferay/frontend/token/definition/internal/TokenDefinitionRegistryImplTest.java new file mode 100644 index 00000000000000..db2d7a5c7db402 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-impl/src/test/java/com/liferay/frontend/token/definition/internal/TokenDefinitionRegistryImplTest.java @@ -0,0 +1,166 @@ +/** + * Copyright (c) 2000-present Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ + +package com.liferay.frontend.token.definition.internal; + +import com.liferay.frontend.token.definition.TokenDefinition; +import com.liferay.portal.kernel.util.HashMapBuilder; +import com.liferay.portal.kernel.util.HashMapDictionary; +import com.liferay.portal.kernel.util.StringUtil; + +import java.io.IOException; +import java.io.InputStream; + +import java.net.URL; + +import java.util.Collection; +import java.util.Dictionary; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Assert; +import org.junit.Test; + +import org.mockito.Mockito; + +import org.osgi.framework.Bundle; +import org.osgi.util.tracker.BundleTracker; + +/** + * @author Iván Zaera + */ +public class TokenDefinitionRegistryImplTest { + + @Test + public void testGetTokenDefinition() throws IOException { + TokenDefinitionRegistryImpl tokenDefinitionRegistryImpl = + new TokenDefinitionRegistryImpl(); + + Bundle bundle = Mockito.mock(Bundle.class); + + Mockito.when( + bundle.getHeaders(Mockito.anyString()) + ).thenReturn( + new HashMapDictionary<>() + ); + + Mockito.when( + bundle.getEntry("META-INF/token-definition.json") + ).thenReturn( + _tokenDefinitionJsonURL + ); + + TokenDefinition tokenDefinition = + tokenDefinitionRegistryImpl.getTokenDefinition(bundle); + + try (InputStream inputStream = _tokenDefinitionJsonURL.openStream()) { + Assert.assertEquals( + StringUtil.read(inputStream), + tokenDefinition.getRawTokenDefinition()); + } + } + + @Test + public void testGetTokenDefinitionPathWithManifestHeader() { + TokenDefinitionRegistryImpl tokenDefinitionRegistryImpl = + new TokenDefinitionRegistryImpl(); + + Bundle bundle = Mockito.mock(Bundle.class); + + Dictionary headers = new HashMapDictionary<>(); + + headers.put("Token-Definition-Path", "WEB-INF/token-definition.json"); + + Mockito.when( + bundle.getHeaders(Mockito.anyString()) + ).thenReturn( + headers + ); + + String tokenDefinitionPath = + tokenDefinitionRegistryImpl.getTokenDefinitionPath(bundle); + + Assert.assertEquals( + "WEB-INF/token-definition.json", tokenDefinitionPath); + } + + @Test + public void testGetTokenDefinitionPathWithoutManifestHeader() { + TokenDefinitionRegistryImpl tokenDefinitionRegistryImpl = + new TokenDefinitionRegistryImpl(); + + Bundle bundle = Mockito.mock(Bundle.class); + + Mockito.when( + bundle.getHeaders(Mockito.anyString()) + ).thenReturn( + new HashMapDictionary<>() + ); + + String tokenDefinitionPath = + tokenDefinitionRegistryImpl.getTokenDefinitionPath(bundle); + + Assert.assertEquals( + "META-INF/token-definition.json", tokenDefinitionPath); + } + + @Test + public void testGetTokenDefinitions() { + TokenDefinitionRegistryImpl tokenDefinitionRegistryImpl = + new TokenDefinitionRegistryImpl(); + + BundleTracker> bundleTracker = + Mockito.mock(BundleTracker.class); + + TokenDefinition tokenDefinition1 = new TokenDefinitionImpl("1"); + TokenDefinition tokenDefinition2 = new TokenDefinitionImpl("2"); + + Map> map = + HashMapBuilder.>put( + Mockito.mock(Bundle.class), + new AtomicReference<>(tokenDefinition1) + ).put( + Mockito.mock(Bundle.class), new AtomicReference<>(null) + ).put( + Mockito.mock(Bundle.class), + new AtomicReference<>(tokenDefinition2) + ).build(); + + Mockito.when( + bundleTracker.getTracked() + ).thenReturn( + map + ); + + tokenDefinitionRegistryImpl.bundleTracker = bundleTracker; + + Collection tokenDefinitions = + tokenDefinitionRegistryImpl.getTokenDefinitions(); + + Assert.assertEquals( + "tokenDefinitions contains 2 items", 2, tokenDefinitions.size()); + + Assert.assertTrue( + "tokenDefinitions contains tokenDefinition1", + tokenDefinitions.contains(tokenDefinition1)); + Assert.assertTrue( + "tokenDefinitions contains tokenDefinition2", + tokenDefinitions.contains(tokenDefinition2)); + } + + private static final URL _tokenDefinitionJsonURL = + TokenDefinitionRegistryImplTest.class.getResource( + "token-definition.json"); + +} \ No newline at end of file diff --git a/modules/apps/frontend-token/frontend-token-definition-impl/src/test/resources/com/liferay/frontend/token/definition/internal/token-definition.json b/modules/apps/frontend-token/frontend-token-definition-impl/src/test/resources/com/liferay/frontend/token/definition/internal/token-definition.json new file mode 100644 index 00000000000000..33339b4db4ab54 --- /dev/null +++ b/modules/apps/frontend-token/frontend-token-definition-impl/src/test/resources/com/liferay/frontend/token/definition/internal/token-definition.json @@ -0,0 +1,109 @@ +{ + "tokenCategories": [ + { + "label": "general", + "name": "general" + }, + { + "label": "layout", + "name": "layout" + } + ], + "tokenSets": [ + { + "label": "grid", + "name": "grid" + }, + { + "label": "links", + "name": "links" + } + ], + "tokens": [ + { + "editorType": "ColorPicker", + "label": "link-color", + "name": "linkColor", + "tokenCategoryName": "general", + "tokenSetName": "links", + "type": "String", + "validValues": [ + { + "label": "salmon", + "value": "Salmon" + }, + { + "label": "red", + "value": "Red" + } + ] + }, + { + "label": "jersey-type", + "name": "jerseyType", + "tokenCategoryName": "colors", + "tokenSetName": "colorCombinations", + "type": "String", + "validValues": [ + { + "label": "home", + "value": "Home" + }, + { + "label": "away", + "value": "Away" + }, + { + "label": "third", + "value": "Third" + } + ] + }, + { + "label": "text-underline", + "name": "linkTextUnderline", + "tokenCategoryName": "general", + "tokenSetName": "links", + "type": "Boolean" + }, + { + "editorType": "ColorPicker", + "label": "link-hover-color", + "name": "linkHoverColor", + "tokenCategoryName": "general", + "tokenSetName": "links", + "type": "String" + }, + { + "label": "text-underline", + "name": "linkHoverTextUnderline", + "tokenCategoryName": "general", + "tokenSetName": "links", + "type": "Boolean" + }, + { + "label": "number-of-columns", + "name": "gridNumberOfColumns", + "tokenCategoryName": "layout", + "tokenSetName": "grid", + "type": "Integer", + "validValues": [ + { + "label": "1", + "value": 1 + }, + { + "label": "3", + "value": 3 + } + ] + }, + { + "label": "gutter", + "name": "gridGutterWidth", + "tokenCategoryName": "layout", + "tokenSetName": "grid", + "type": "String" + } + ] +} \ No newline at end of file