ZK - Open Source Ajax Java FrameworkZK - Open Source Ajax Java Framework

Inter Portlet Communication on Liferay

mixgho
23 Jan 2012 09:53:37 GMT
23 Jan 2012 09:53:37 GMT

Hi,
I'm trying to do the Inter Portlet Communication (IPC) based on Portlet 2.0 API on Liferay.
For my portlets I use custom Portlet extending the DHtmlLayoutPortlet and I also have <supported-publishing-event> and <supported-processing-event> definitions in portlet.xml.

Problem is - how do I fire an event from ZUL page or from BindingComposer so it gets propagated to processAction() method or custom method annotated with @ProceesAction/Event annotation on Portlet class?
In JSP portlet page I would use <portlet:actionURL name="actionName"></portlet:actionURL> but how to do this in ZUL page?

Thanks in advance!

mixgho
23 Jan 2012 09:56:45 GMT
23 Jan 2012 09:56:45 GMT

I've tried to use the

Clients.evalJavaScript("Liferay.fire('actionName', {param:value});");
but with no luck :(

vincentjian
31 Jan 2012 09:53:54 GMT
31 Jan 2012 09:53:54 GMT

Hi,

I tried using Application scope EventQueue to communication two portlets that works fine.

zul in portlet 1:

<zk>
	<window title="portlet1" border="normal" width="200px" height="100px" apply="demo.WindowComposer">
		<button id="btn" label="change label in portlet2" ></button>
	</window>
</zk>

composer class in portlet 1:
public class WindowComposer extends GenericForwardComposer {

	private EventQueue eq;
	
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
	}
	
	public void onClick$btn() {
		eq = EventQueues.lookup("doPortlet", EventQueues.APPLICATION, false);
		System.out.println("portlet1: " + eq.toString());
		eq.publish(new Event("onButtonClick"));
	}
}

zul in portlet 2:

<zk>
	<window title="portlet2" border="normal" width="200px" height="100px" apply="demo.WindowComposer2">
		<label id="lbl" value="label in portlet2" ></label>
	</window>
</zk>

composer class in portlet 2:

public class WindowComposer2 extends GenericForwardComposer {

	private Label lbl;
	private EventQueue eq;
	
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);	
		eq = EventQueues.lookup("doPortlet", EventQueues.APPLICATION, true);
		System.out.println("portlet2: " + eq.toString());
		eq.subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				System.out.println(event.getName());
				lbl.setValue("Value Changed!!!");
			}
		});
	}
}

mixgho
31 Jan 2012 11:41:50 GMT
31 Jan 2012 11:41:50 GMT

Yes, this works fine, but I wanted to use the standard Portlet API - it enables Portal <-> Portlet comm, Portlet1.war <-> Portlet2.war portlet communication etc.

Nevertheless, I'm using the EventQueus now, but subscribe Event is not picked up by Binding API - is there a way to invoke something like new AnnotateDataBinder().loadAll(); from subscribe Event?

vincentjian
1 Feb 2012 09:11:53 GMT
1 Feb 2012 09:11:53 GMT

Hi,

If you use <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?> in zul page, you could use the following code to get binder in composer:

public class WindowComposer2 extends GenericForwardComposer {

	private Label lbl;
	private EventQueue eq;
	
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);	
		eq = EventQueues.lookup("doPortlet", EventQueues.APPLICATION, true);
		eq.subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				AnnotateDataBinder binder = (AnnotateDataBinder) page.getAttribute("binder");
				binder.loadAll();
			}
		});
	}
}

mixgho
1 Feb 2012 15:06:22 GMT
1 Feb 2012 15:06:22 GMT

I'm trying to use the new ZK6 Binding API, but it introduces some Lifecycles and such stuff, so Binder is not accessible most of the time :(
I've explained the problem here.

Extending BindComposer has no effect (class behaves like normal POJO).
Binder object is accesible only in @Command methods and Validators.
How can I send message from one composer to another with data refresh in target Composer?

vincentjian
17 Apr 2012 06:15:50 GMT
17 Apr 2012 06:15:50 GMT

Hi mixgho,

I have write a small sample that can communicate between two portlets:
portlet1.zul

<window title="Hello MVVM" border="normal" width="100%" height="100%"
    apply="org.zkoss.bind.BindComposer" viewModel="@id('portlet1') @init('demo.PortletVM1')">
    <listbox model="@load(portlet1.books)">
        <template name="model" var="selected">
            <listitem onClick="@global-command('showDetail', book=selected)">
                <listcell label="@bind(selected.name)" ></listcell>
            </listitem>
        </template>
    </listbox>
</window>

PortletVM1.java
public class PortletVM1{
    private List<Book> _books;
    
    public PortletVM1() {
        _books = new ArrayList<Book>();
        _books.add(new Book("Hello! HTML5 (Introducing HTML5)", 400 , 20));
        _books.add(new Book("ASP.NET 4.0 2/e", 250 , 75));
        _books.add(new Book("jQuery in Action 2/e", 510 , 52));
    }

    public ListModel<Book> getBooks() {
        return new ListModelList<Book>(_books);
    }
}

portlet2.zul
<window title="Hello MVVM" border="normal" width="100%" height="100%"
    apply="org.zkoss.bind.BindComposer" viewModel="@id('portlet2') @init('demo.PortletVM2')"
    binder="@init(queueScope='group')">
    <grid>
        <rows>
            <row>Name: <label value="@bind(portlet2.book.name)" ></label></row>
            <row>Price: <label value="@bind(portlet2.book.price)" ></label></row>
            <row>Stock: <label value="@bind(portlet2.book.stock)" ></label></row>
        </rows>
    </grid>
</window>

PortletVM2.java
public class CenterVM {
    private Book _book;
    
    public Book getBook() {
        return _book;
    }
    
    @GlobalCommand @NotifyChange("book")
    public void show(@BindingParam("book") Book selected) {
        _book = selected;
    }
}