Invient Charts: can't get to work inside of LifeRay Vaadin Portlet

I’ve tried just about everything, but still see a ‘blank’ screen. Is this related to the way Vaadin and LifeRay interact? Yes, I’ve copied the js files from the Invient Charts add-on and put them under the VAADIN folder. Porltet, servlet, web.xml, and exact copy of a chart are below! Please help!

This is my main ‘portlet’ class, com.isidorey.vaadin.portlet.ChartPortlet.java

public class ChartPortlet extends Application {
	/*
	 * Portlet
	 */
	Window main = new Window();
	PortletApplicationContext2 ctx;
	String portletEmail;
	String portletSession;
	String WINDOW_NAME = "Charts";
	/*
	 * Logging
	 */
	private Logger log = Logger.getLogger(ChartPortlet.class.getName());

	@Override
	public void init() {
		/*
		 * Portlet settings
		 */
		main.setName(WINDOW_NAME);
		main.setSizeFull();
		setMainWindow(main);
		/*
		 * Set listener
		 */
		if (getContext() instanceof PortletApplicationContext2) {
			ctx = (PortletApplicationContext2) getContext();
			ctx.addPortletListener(this, new ChartPortletListener());
		} else {
			new VaadinError(getMainWindow(), "Portlet Error",
					"Not inited via portal.");
		}
	}

	private class ChartPortletListener implements PortletListener {
		@Override
		public void handleRenderRequest(RenderRequest request,
				RenderResponse response, Window window) {
			/*
			 * Remove all components on refresh
			 */
			main.removeAllComponents();
			/*
			 * Portal variables
			 */
			ThemeDisplay themeDisplay = (ThemeDisplay) (request
					.getAttribute(WebKeys.THEME_DISPLAY));
			/*
			 * Set globals
			 */
			portletEmail = themeDisplay.getUser().getEmailAddress();
			portletSession = request.getRequestedSessionId();
			log.info(portletEmail);
			log.info(portletSession);
			/*
			 * Show Chart
			 */
			LineChart line = new LineChart();
			InvientCharts lineChart = line.line();

			VerticalLayout verticalLayout = new VerticalLayout();
			verticalLayout.setHeight("800px");
			verticalLayout.setWidth("600px");
			verticalLayout.setMargin(true);
			verticalLayout.addComponent(lineChart);

			main.addComponent(verticalLayout);
		}

		@Override
		public void handleEventRequest(EventRequest request,
				EventResponse response, Window window) {

		}

		/*
		 * Unused
		 */
		@Override
		public void handleActionRequest(ActionRequest request,
				ActionResponse response, Window window) {
		}

		@Override
		public void handleResourceRequest(ResourceRequest request,
				ResourceResponse response, Window window) {
		}

	}

}

This is my custom servlet class, com.isidorey.vaadin.portlet.CustomServlet.java

public class CustomServlet extends ApplicationServlet {
	/*
	 * Logging
	 */
	private Logger log = Logger.getLogger(CustomServlet.class.getName());

    @Override
    protected void writeAjaxPageHtmlVaadinScripts(Window window,
            String themeName, Application application, BufferedWriter page,
            String appUrl, String themeUri, String appId,
            HttpServletRequest request) throws ServletException, IOException {
    	log.info("THIS IS GETTING EXEC");
        page.write("<script language='javascript' src='./VAADIN/jquery/jquery-1.4.4.min.js'></script>\n");
        page.write("<script language='javascript' src='./VAADIN/js/highcharts.js'></script>\n");
        page.write("<script language='javascript' src='./VAADIN/js/modules/exporting.js'></script>\n");
        super.writeAjaxPageHtmlVaadinScripts(window, themeName, application,
                page, appUrl, themeUri, appId, request);
    }

}

This is my web.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>IsidoreyVaadinChartPortlets</display-name>
	<context-param>
		<description>Vaadin production mode</description>
		<param-name>productionMode</param-name>
		<param-value>false</param-value>
	</context-param>
	<servlet>
		<servlet-name>Isidoreyvaadingraphingportlets Application</servlet-name>
		<servlet-class>com.isidorey.vaadin.portlet.CustomServlet</servlet-class>
		<init-param>
			<description>Vaadin application class to start</description>
			<param-name>application</param-name>
			<param-value>com.isidorey.vaadin.portlet.ChartPortlet</param-value>
		</init-param>
		<init-param>
			<param-name>widgetset</param-name>
			<param-value>com.isidorey.vaadin.portlet.widgetset.IsidoreyvaadingraphingportletsWidgetset</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Isidoreyvaadingraphingportlets Application</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Isidoreyvaadingraphingportlets Application</servlet-name>
		<url-pattern>/VAADIN/*</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<jsp-config>
  	<taglib>
  		<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>
  		<taglib-location>
  			/WEB-INF/tld/liferay-portlet.tld
  		</taglib-location>
  	</taglib>
  	<taglib>
        <taglib-uri>http://liferay.com/tld/aui</taglib-uri>
        <taglib-location>/WEB-INF/tld/liferay-aui.tld</taglib-location>
    </taglib>
  </jsp-config>
  <session-config>
    <session-timeout>90</session-timeout>
  </session-config>
</web-app>

This is my implementation of the line chart example

public class LineChart {
	
	public InvientCharts line() {
		InvientChartsConfig chartConfig = new InvientChartsConfig();
		chartConfig.getGeneralChartConfig().setMargin(new Margin());
		chartConfig.getGeneralChartConfig().getMargin().setRight(130);
		chartConfig.getGeneralChartConfig().getMargin().setBottom(25);

		chartConfig.getTitle().setX(-20);
		chartConfig.getTitle().setText("Monthly Average Temperature");
		chartConfig.getSubtitle().setText("Source: WorldClimate.com");
		chartConfig.getTitle().setX(-20);

		CategoryAxis categoryAxis = new CategoryAxis();
		categoryAxis.setCategories(Arrays.asList("Jan", "Feb", "Mar", "Apr",
				"May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"));
		LinkedHashSet<XAxis> xAxesSet = new LinkedHashSet<InvientChartsConfig.XAxis>();
		xAxesSet.add(categoryAxis);
		chartConfig.setXAxes(xAxesSet);

		NumberYAxis numberYAxis = new NumberYAxis();
		numberYAxis.setTitle(new AxisTitle("Temperature (°C)"));
		NumberPlotLine plotLine = new NumberPlotLine("TempAt0");
		plotLine.setValue(new NumberValue(0.0));
		plotLine.setWidth(1);
		plotLine.setZIndex(1);
		plotLine.setColor(new RGB(128, 128, 128));
		numberYAxis.addPlotLine(plotLine);
		LinkedHashSet<YAxis> yAxesSet = new LinkedHashSet<InvientChartsConfig.YAxis>();
		yAxesSet.add(numberYAxis);
		chartConfig.setYAxes(yAxesSet);

		Legend legend = new Legend();
		legend.setLayout(Layout.VERTICAL);
		Position legendPos = new Position();
		legendPos.setAlign(HorzAlign.RIGHT);
		legendPos.setVertAlign(VertAlign.TOP);
		legendPos.setX(-10);
		legendPos.setY(100);
		legend.setPosition(legendPos);
		legend.setBorderWidth(0);
		chartConfig.setLegend(legend);

		// Series data label formatter
		LineConfig lineCfg = new LineConfig();
		chartConfig.addSeriesConfig(lineCfg);
		// Tooltip formatter
		chartConfig
				.getTooltip()
				.setFormatterJsFunc(
						"function() { "
								+ " return '<b>' + this.series.name + '</b><br/>' +  this.x + ': '+ this.y +'°C'"
								+ "}");

		InvientCharts chart = new InvientCharts(chartConfig);

		XYSeries seriesData = new XYSeries("Tokyo");
		seriesData.setSeriesPoints(getPoints(seriesData, 7.0, 6.9, 9.5, 14.5,
				18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6));
		chart.addSeries(seriesData);

		seriesData = new XYSeries("New York");
		seriesData.setSeriesPoints(getPoints(seriesData, -0.2, 0.8, 5.7, 11.3,
				17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5));
		chart.addSeries(seriesData);

		seriesData = new XYSeries("Berlin");
		seriesData.setSeriesPoints(getPoints(seriesData, -0.9, 0.6, 3.5, 8.4,
				13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0));
		chart.addSeries(seriesData);

		seriesData = new XYSeries("London");
		seriesData.setSeriesPoints(getPoints(seriesData, 3.9, 4.2, 5.7, 8.5,
				11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8));
		chart.addSeries(seriesData);

		return chart;
	}

	private static LinkedHashSet<DecimalPoint> getPoints(Series series,
			double... values) {
		LinkedHashSet<DecimalPoint> points = new LinkedHashSet<DecimalPoint>();
		for (double value : values) {
			points.add(new DecimalPoint(series, value));
		}
		return points;
	}
}

Please check if the javascript files (js/highcharts.js and js/modules/exporting.js) required by InvientCharts are loaded correctly.

They are being loaded. I have upgraded to the newest 0.8.3 demos, and split apart the project from there. I’ve found the problem to be related to the context of the window (when I try to make it PortletApplicationContext2 instead of WebApplicationContext).

Here is base version of what works (renders a chart inside of Liferay), but doesn’t allow me to get any params from the context of PortletApplicationContext2 (because only web.xml is in WEB-INF at this point)

demo/com.invient.vaadin.InvientChartsDemoApp

package com.invient.vaadin;

import com.invient.vaadin.charts.InvientCharts;
import com.isidorey.vaadin.charts.area.line.Basic;
import com.vaadin.Application;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

@SuppressWarnings("serial")
public class InvientChartsDemoApp extends Application {

    Window main = new Window();

    @Override
    public void init() {

        setTheme("chartdemo");

        main.setSizeFull();
        setMainWindow(main);
       
        VerticalLayout container = new VerticalLayout();
        container.setSpacing(true);
        container.setMargin(true);
        container.setSizeFull();

        com.vaadin.charts.area.line.Basic myChart = new Basic();
        InvientCharts chart = myChart.getChart();

        chart.setSizeFull();
        chart.setStyleName("v-chart-min-width");
        chart.setHeight("410px");

        container.setStyleName("v-chart-master-detail");
        container.addComponentAsFirst(chart);

        main.addComponent(container);
    }
}

My problem is when I add the necessary Liferay XML files (liferay-display.xml, liferay-plugin-package.properties, liferay-portlet.xml, portlet.xml), the context changes from WebApplicationContext to PortletApplicationContext2 (good for me, bad for charts), and nothing gets rendered using the same code :confused:

It seems that the custom
ApplicationServlet
doesn’t get called because apparently it’s supposed to be used with
WebApplicationContext
.

I got this working by creating almost identical class that doesn’t inherit from
ApplicationServlet
but
ApplicationPortlet2
and changing the portlet class in portlet.xml.

[u]

  1. Create MyApplicationPortlet2.java
    [/u]
import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.ApplicationPortlet2;
import java.io.BufferedWriter;
import java.io.IOException;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.apache.log4j.Logger;

public class MyApplicationPortlet2 extends ApplicationPortlet2 {
    
    private Logger log = Logger.getLogger(MyApplicationPortlet2.class);

    @Override
    protected void writeAjaxPageHtmlVaadinScripts(RenderRequest request, RenderResponse response, 
    BufferedWriter page, Application application, String themeName) throws IOException, PortletException {

        page.write("<script type=\"text/javascript\">\n");
        page.write("//<![CDATA[\n");
        page.write("document.write(\"<script language='javascript' src='/html/VAADIN/js/jquery-1.5.1.min.js'><\\/script>\");\n");
        page.write("document.write(\"<script language='javascript' src='/html/VAADIN/js/highcharts.js'><\\/script>\");\n");
        page.write("//]]>\n</script>\n");
        
        log.info("jQuery and HighCharts javascript loaded.");
        
        super.writeAjaxPageHtmlVaadinScripts(request, response, page, application, themeName);
    }
    
}


2. Change the portlet-class in portlet.xml

<portlet-class>com.example.MyApplicationPortlet2</portlet-class>

I’m not yet quite sure about hard-coding the javascript files’ location, but atm it doesn’t seem to be a problem.

If you still see a blank page instead of the charts, check if the scripts actually load by using firebug. Hope this helps you.

There is no (user-written) servlet when developing JSR-286 portlets - all communication goes via the portlet class.

You should use getStaticFilesLocation(request) instead of “/html”.

I tried to create the file, as Miku Laitinen says, but does not work.
The portlet is displayed, but invient not.
How do I know the location of my javascript?

name=Provam
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=LGPL
portal-dependency-jars=\
    vaadin.jar,\
    eclipselink.jar,\
    ejb3-persistence.jar,\
    dom4j.jar,\
    VaadinVisualizations2.1.jar,\
    gwt-visualization.jar,\
    gwt-ajaxloader.jar,\
    highcharts-0.1.0.jar,\
    invientcharts-0.8.6.jar

As u can see I tried to use a lot of addons for chart, but no one of them works.
I think the reason is javascript

<?xml version="1.0"?>

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0">
	<portlet>
		<portlet-name>provam</portlet-name>
		<display-name>Provam</display-name>
		
<portlet-class>provam.MyApplicationPortlet2</portlet-class>
		<init-param>
			<name>application</name>
			<value>provam.ProvamApplication</value>
		</init-param>
		<expiration-cache>0</expiration-cache>
		<supports>
			<mime-type>text/html</mime-type>
		</supports>
		<portlet-info>
			<title>Provam</title>
			<short-title>Provam</short-title>
			<keywords>Provam</keywords>
		</portlet-info>
		<security-role-ref>
			<role-name>administrator</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>guest</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>power-user</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>user</role-name>
		</security-role-ref>
	</portlet>
</portlet-app>

I have used the Vaadim control Panel for liferay to compile widgets set and it says “all ok”

The only graph addonn that work is timeline… Why

This is my example code :

	public void init() {
		Window window = new Window();
		setTheme("chartdemo");
		window.setSizeFull();
        setMainWindow(window);
        InvientChartsConfig chartConfig = new InvientChartsConfig();
        chartConfig.getGeneralChartConfig().setType(SeriesType.BAR);
        BarConfig barCfg = new BarConfig();
        barCfg.setDataLabel(new DataLabel());
        barCfg.setColor(new Color.RGB(0, 255, 0));
        XYSeries seriesData = new XYSeries("Test", SeriesType.BAR, barCfg);
        seriesData.addPoint(new DecimalPoint(seriesData, 107));
        InvientCharts chart = new InvientCharts(chartConfig);
        chart.addSeries(seriesData);
        window.addComponent(chart);

Probably the simplest way is to add to liferay-portlet.xml:


<header-portlet-javascript>
/js/inv/highcharts.js
</header-portlet-javascript>

Not only is it the simplest, but it is almost the correct way to include JS resources in a portlet. The OPs code w/ the embedded junk is definitely the wrong way to go.

It would have been more correct to use as it allows the portlets to begin rendering on the page rather than waiting on js to load.