Commit 564bdc01 authored by Woonsan Ko's avatar Woonsan Ko

CRISP-35: Adding Hystrix integration example in demo

parent 3f9442f4
......@@ -65,6 +65,8 @@
<hippo.addon-crisp.version>${project.version}</hippo.addon-crisp.version>
<!-- ***END temporary override of versions*** -->
<hystrix-javanica.version>1.5.12</hystrix-javanica.version>
<forge.exdocpickerbase.version>5.0.2</forge.exdocpickerbase.version>
<commons-lang.version>2.6</commons-lang.version>
......@@ -125,6 +127,12 @@
<version>${hippo.addon-crisp.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>${hystrix-javanica.version}</version>
</dependency>
<dependency>
<groupId>org.onehippo.forge.exdocpickerbase</groupId>
<artifactId>exdocpickerbase-field</artifactId>
......
......@@ -37,3 +37,6 @@ definitions:
jcr:primaryType: hst:sitemapitem
hst:componentconfigurationid: hst:pages/newslist
hst:relativecontentpath: ${parent}/${1}
/products:
jcr:primaryType: hst:sitemapitem
hst:componentconfigurationid: hst:pages/productspage
......@@ -23,3 +23,6 @@ definitions:
/newspage-main:
jcr:primaryType: hst:template
hst:renderpath: webfile:/freemarker/hstdefault/newspage-main.ftl
/productspage-main:
jcr:primaryType: hst:template
hst:renderpath: webfile:/freemarker/hippoaddoncrispdemo/productspage-main.ftl
......@@ -79,3 +79,10 @@ definitions:
hst:componentclassname: org.onehippo.cms7.crisp.demo.components.NewsContentComponent
hst:template: newspage-main
hst:xtype: hst.item
/productspage:
jcr:primaryType: hst:containercomponentfolder
/main:
.meta:residual-child-node-category: content
jcr:primaryType: hst:containercomponent
hst:label: Products Page Main
hst:xtype: hst.vbox
definitions:
config:
/hst:hst/hst:configurations/hippoaddoncrispdemo/hst:pages/productspage:
jcr:primaryType: hst:component
hst:referencecomponent: hst:abstractpages/base
/main:
jcr:primaryType: hst:component
hst:componentclassname: productListComponent
hst:template: productspage-main
/container:
jcr:primaryType: hst:containercomponentreference
hst:referencecomponent: productspage/main
definitions:
config:
/hst:hst/hst:configurations/hippoaddoncrispdemo/hst:workspace/hst:sitemenus/main/products:
jcr:primaryType: hst:sitemenuitem
hst:referencesitemapitem: products
<#include "../include/imports.ftl">
<h3>Products</h3>
<#if products?has_content??>
<ul>
<#list products as product>
<li>
[${product.sku!}] ${product.extendedData.title!}
(${product.extendedData.description!})
</li>
</#list>
</ul>
</#if>
<div>
<@hst.include ref="container"/>
</div>
......@@ -30,6 +30,11 @@
<artifactId>hippo-addon-crisp-hst</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
......
/*
* Copyright 2017 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onehippo.cms7.crisp.demo.components;
import java.util.Collection;
import org.hippoecm.hst.component.support.bean.BaseHstComponent;
import org.hippoecm.hst.core.component.HstRequest;
import org.hippoecm.hst.core.component.HstResponse;
import org.hippoecm.hst.core.parameters.ParametersInfo;
import org.onehippo.cms7.crisp.demo.model.Product;
import org.onehippo.cms7.crisp.demo.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
/**
* Spring managed component to auto-wire {@link ProductService} bean in Spring ApplicationContext.
* <P>
* Note: Since Hippo CMS v12.1, you don't need to set the FQCN of this class to the {@link Service} annotation any more.
* If you skip the value of the annotation, then Spring will register this component bean as camel-cased simple class name.
* i.e, "productListComponent".
* </P>
* <P>
* Therefore, as long as you set <code>@hst:componentclassname</code> property to the logical bean name (e.g, "productListComponent"),
* it will work fine.
* Also, in this case, note that if this spring-managed component needs to provide a {@link ParametersInfo} type,
* please set <code>@hst:parametersinfoclassname</code> additionally in the HST Component configuration node.
* </P>
*
* @see <a href="https://www.onehippo.org/library/concepts/web-application/spring-managed-hst-components.html">https://www.onehippo.org/library/concepts/web-application/spring-managed-hst-components.html</a>
*/
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ProductListComponent extends BaseHstComponent {
private static Logger log = LoggerFactory.getLogger(ProductListComponent.class);
@Autowired
private ProductService productService;
@Override
public void doBeforeRender(final HstRequest request, final HstResponse response) {
super.doBeforeRender(request, response);
Collection<Product> products = productService.getProductCollection();
request.setAttribute("products", products);
}
}
/*
* Copyright 2017 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onehippo.cms7.crisp.demo.model;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="extendedData")
public class ExtendedData {
private String title;
private String type;
private String uri;
private String description;
@XmlElement
public String getTitle() {
return title;
}
public void setTitle(String value) {
this.title = value;
}
@XmlElement
public String getType() {
return type;
}
public void setType(String value) {
this.type = value;
}
@XmlElement
public String getUri() {
return uri;
}
public void setUri(String value) {
this.uri = value;
}
@XmlElement
public String getDescription() {
return description;
}
public void setDescription(String value) {
this.description = value;
}
}
......@@ -15,6 +15,7 @@
*/
package org.onehippo.cms7.crisp.demo.model;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
......@@ -27,7 +28,9 @@ public class Product {
private String sku;
private String description;
private String name;
private ExtendedData extendedData;
@XmlElement(name = "SKU")
@JsonProperty("SKU")
public String getSku() {
return sku;
......@@ -37,6 +40,7 @@ public class Product {
this.sku = sku;
}
@XmlElement
public String getDescription() {
return description;
}
......@@ -45,6 +49,7 @@ public class Product {
this.description = description;
}
@XmlElement
public String getName() {
return name;
}
......@@ -53,4 +58,13 @@ public class Product {
this.name = name;
}
@XmlElement
public ExtendedData getExtendedData() {
return extendedData;
}
public void setExtendedData(ExtendedData value) {
this.extendedData = value;
}
}
/*
* Copyright 2017 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onehippo.cms7.crisp.demo.service;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.onehippo.cms7.crisp.api.broker.ResourceServiceBroker;
import org.onehippo.cms7.crisp.api.resource.Resource;
import org.onehippo.cms7.crisp.api.resource.ResourceBeanMapper;
import org.onehippo.cms7.crisp.demo.model.Product;
import org.onehippo.cms7.crisp.hst.module.CrispHstServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import static org.onehippo.cms7.crisp.demo.Constants.RESOURCE_SPACE_DEMO_PRODUCT_CATALOG;
/**
* Example business service in Circuit Breaker pattern with {@link HystrixCommand} annotation for fallback
* in case of exceptions or timeout (1000ms by default according to Hystrix documentation).
*
* @see <a href="https://github.com/Netflix/Hystrix/wiki/How-it-Works">https://github.com/Netflix/Hystrix/wiki/How-it-Works</a>
* @see <a href="https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.thread.timeoutInMilliseconds">https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.thread.timeoutInMilliseconds</a>
*/
@Service
public class ProductService {
private static Logger log = LoggerFactory.getLogger(ProductService.class);
private static final URL DEMO_LOCAL_CACHED_PRODUCTS_JSON_URL = ProductService.class
.getResource("cached-products.json");
private ObjectMapper objectMapper = new ObjectMapper();
/**
* The example Hystrix command operation with a fallback method and execution timeout (3 seconds in this demo).
* <P>
* <EM>Tip:</EM> You might want to put a debugger inside the method to make a <strong>timeout</strong> for a demo.
* Or, you can set {@code productCatalogs} to null to throw an exception for demonstration purpose as well.
* </P>
* @return
*/
@HystrixCommand(
fallbackMethod = "getReliableProductCollection",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
}
)
public Collection<Product> getProductCollection() {
Resource productCatalogs = null;
ResourceServiceBroker resourceServiceBroker = CrispHstServices.getDefaultResourceServiceBroker();
final Map<String, Object> pathVars = new HashMap<>();
productCatalogs = resourceServiceBroker.findResources(RESOURCE_SPACE_DEMO_PRODUCT_CATALOG, "/products/",
pathVars);
ResourceBeanMapper resourceBeanMapper = resourceServiceBroker
.getResourceBeanMapper(RESOURCE_SPACE_DEMO_PRODUCT_CATALOG);
Collection<Product> productCollection = resourceBeanMapper.mapCollection(productCatalogs.getChildren(),
Product.class);
return productCollection;
}
/**
* A reliable fallback operation example, reading cached data from a JSON data file in the classpath.
* @return
*/
public Collection<Product> getReliableProductCollection() {
List<Product> productsList = new LinkedList<>();
InputStream is = null;
BufferedInputStream bis = null;
try {
is = DEMO_LOCAL_CACHED_PRODUCTS_JSON_URL.openStream();
bis = new BufferedInputStream(is);
JsonNode root = objectMapper.readTree(bis);
for (Iterator<JsonNode> it = root.elements(); it.hasNext();) {
JsonNode elem = it.next();
Product product = objectMapper.convertValue(elem, Product.class);
productsList.add(product);
}
} catch (Exception e) {
log.error("Failed to read data from json resource file.", e);
} finally {
IOUtils.closeQuietly(bis);
IOUtils.closeQuietly(is);
}
return productsList;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 Hippo B.V. (http://www.onehippo.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
<aop:aspectj-autoproxy />
<bean id="hystrixAspect"
class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect">
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 Hippo B.V. (http://www.onehippo.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
<!-- (HST)Components Annotation Scanning -->
<context:component-scan base-package="org.onehippo.cms7.crisp.demo.components,org.onehippo.cms7.crisp.demo.service" />
</beans>
\ No newline at end of file
[
{
"SKU": "4150349",
"description": "MultiSync X431BT - 109.22 cm (43 \") , 1920 x 480, 16:4, 500 cd\/m\u00b2, 3000:1, 8 ms",
"name": "NEC MultiSync X431BT",
"extendedData": {
"title": "NEC MultiSync X431BT",
"type": "Link",
"uri": "Incentro-HIC-Site\/-\/products\/4150349",
"description": "MultiSync X431BT - 109.22 cm (43 \") , 1920 x 480, 16:4, 500 cd\/m\u00b2, 3000:1, 8 ms"
}
},
{
"SKU": "4696003",
"description": "PA271W, 68.58 cm (27 \") LCD, 2560 x 1440, 6ms, 1000:1, 300cd\/m2, 1.073B",
"name": "NEC PA271W",
"extendedData": {
"title": "NEC PA271W",
"type": "Link",
"uri": "Incentro-HIC-Site\/-\/products\/4696003",
"description": "PA271W, 68.58 cm (27 \") LCD, 2560 x 1440, 6ms, 1000:1, 300cd\/m2, 1.073B"
}
},
{
"SKU": "4017125",
"description": "LCD\/TFT desk mount",
"name": "Newstar FPMA-D700D",
"extendedData": {
"title": "Newstar FPMA-D700D",
"type": "Link",
"uri": "Incentro-HIC-Site\/-\/products\/4017125",
"description": "LCD\/TFT desk mount"
}
}
]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment