[Logo] RSF Discussions Forum
  [Search] Search   [Recent Topics] Recent Topics   [Members]  Member Listing   [Groups] Back to home page 
[Register] Register / 
[Login] Login 
Simple Lists  XML
Forum Index -> RSF Help and Problems
Author Message
stevegithens
Request-scope Wrangler

Joined: 04/04/2006 20:34:52
Messages: 84
Location: ooeepooee
Offline

I need to render the Nav Links at the top of an RSF Sakai tool, but they will be different depending on what permissions you have. I am unsure of the best practice way to do this using a Java Producer.

The final result should look like:

<div class="navIntraTool">
<a href="one.html">Nav1</a>
<a href="two.html">Nav2</a>
<a href="three.html">Nav3</a>
</div>

So I have the template as follows:

<div class="navIntraTool" rsf:id="navlinks:">
<a href="overview.html" rsf:id="navlink">Navigational Links</a>
</div>

I imagine then that I'd create a UIBranchContainer, then add a UIReplicator, then the UIInternalLink to that.

However, the UIReplicator doesn't have any 'make' methods so I am unsure if this is the correct route.

My list of Navigation Links will come from a Service that checks your permissions. Returning a List of NavLink, which just has two properties for the Link Label and View ID to go to.

I imagine I'll be generating lots of simple lists like this.
[WWW]
antranig
Request-scope Wrangler

Joined: 03/04/2006 13:29:55
Messages: 643
Offline

Replicators (and Switches) are only needed when using XML producers, you can ignore them - in Java, just use a "for" loop!

In IKAT, "repeated" components are signalled by putting colons into the ids of the thing being repeated. You're nearly right with your template, only since it is the link you want repeating and not the div, you want the colon id in the link.

So what you actually want is this:

<div class="navIntraTool" >
<a href="overview.html" rsf:id="navlink:">Nav1</a> (spacer between links)
<a href="overview.html" rsf:id="navlink:">Nav2</a>
</div>

(It's a good idea that whenever you have something that you may repeat, to have at least TWO examples of it in the template, for a start it gives you somewhere to put any spacing material. There is also an annoying bug with rendering repeated single components in 0.6.0, fixed in 0.6.1)

Then in your producer, just keep emitting as many UIInternalLink objects as you need, with the "navlink:" ID. For example,

for (int i = 0; i < links.size(); ++ i) {
//... make viewparams here
UIInternalLink.make(parent, "navlink:", "Link text "+i, viewparams);
}

If you leave "Link text" as null, you will get whatever is in the template.

Due to IKAT magic, you will also get the "glue" (spacer between links) repeated for free
stevegithens
Request-scope Wrangler

Joined: 04/04/2006 20:34:52
Messages: 84
Location: ooeepooee
Offline

Thanks. IKAT is pretty slick. I should go read the IKAT algoritm page.

One more silly question:

What's the easiest way to pass some parameters between Views.

To start, I just want to dynamically generate some UIInternalLinks. With just a servlet I would go:

I'm imagining:

<a href="newviewid?myval=1">One</a>
<a href="newviewid?myval=2">Two</a>

I may eventually want to use a flow or something, but would like to start very simple. Which is enough to get my app rolling.

As we're supposed to be keeping strict seperations of concerns I'm not sure how to get that parameter into the UIInternalLink and back out on the destination ViewComponentProducer.

Does this require implementing the respective ViewParamsReceiver and ViewParamsReporter?

Thanks!
[WWW]
antranig
Request-scope Wrangler

Joined: 03/04/2006 13:29:55
Messages: 643
Offline

The key to passing things between views is in your other question, on ViewParameters. A ViewParameters object summarises all the state that is held in a particular URL (there is one-to-one conversion from one to the other, generally done by BasicViewParametersParser, but you won't need to bother with this unless you want something special).

So, for your case for example, you would define

class MyViewParameters extends SimpleViewParameters {
public int myval;

public StringList getAttributeFields() {
StringList togo = super.getAttributeFields().copy();
togo.add("myval");
}

public ViewParameters copyBase() {
MyViewParameters togo = (MyViewParameters)super.copyBase();
togo.myval = myval;
return myval;
}

}


You then construct a new ViewParameters object to be the last argument of the UIInternalLink constructor. The ViewProducer for view "newviewid" then registers itself as accepting MyViewParameter objects by returning an example from its getViewParameters method.

The copyBase() method is necessary for the framework but can be useful for you as well - ViewParameters objects could get bigger, and you can often be making up a whole batch of links that are the same apart from just one field - so in the loop I wrote in the message earlier, you might have a call to copyBase() to make the new ViewParameters for each link rather than constructing one from scractch each time round the loop.

Sorry that the ViewParameters derivation process isn't quite as slick as it should be, this is all pending a cleanup somewhere around 0.7 time when ViewParameters will just be a "holder" for a completely free object you define yourself. For now your own fields get "mixed in" rather with the housekeeping fields in the base class.

Note that i) you don't need to make "myval" a pea-like field if you don't want to, getters and setters work just fine too ii) you can precompute the "attributeFields" list if you're worried about efficiency.

Note that you get reasonable type conversion for ViewParameters fields for free - the system knows how to deal with most sensible primitive types and leaf types by itself so you don't get messed up with all the grotty bits of URL parsing and conversions.
stevegithens
Request-scope Wrangler

Joined: 04/04/2006 20:34:52
Messages: 84
Location: ooeepooee
Offline

I'm still missing some link of the puzzle.

I've created my own view parameters:

Code:
 public class TopicViewParameters extends SimpleViewParameters {
 	public String rdfuri;
 	
 	public StringList getAttributeFields()
 	{
 		StringList togo = super.getAttributeFields().copy();
 		togo.add("rdfuri");
 		return togo;
 	}
 	
 	public ViewParameters copyBase() 
 	{
 		TopicViewParameters togo = (TopicViewParameters)super.copyBase();
 		togo.rdfuri = rdfuri;
 		return togo;
 	}
 }


then I have my first ViewProducer:

Code:
 public class OverviewProducer implements ViewComponentProducer, DefaultView
 {
 	private List navlinksList;
 	private TopicService ts = null;
 	
 	public void setTopicService(TopicService ts)
 	{
 		this.ts = ts;
 	}
 	
 	public String getViewID() {
 		return "overview";
 	}
 	
 	public void setNavlinksList(List navlinks)
 	{
 		this.navlinksList = navlinks;
 	}
 
 	public void fillComponents(UIContainer arg0, ViewParameters arg1, ComponentChecker arg2) {
 		List links = new ArrayList();
 		
 		if (ts.isAllowedEdit())
 			links.add(new NavLink("chemtest2", "Add Topic"));
 		
 		for (Iterator i = links.iterator(); i.hasNext();)
 		{
 			NavLink l = (NavLink) i.next();
 			TopicViewParameters tvp = new TopicViewParameters();
 			tvp.viewID = l.getLink();
 			tvp.rdfuri = "topicuri"; // Just an example test parameter
 			
 			UIInternalLink.make(arg0, ComponentIDs.navlink, l.getLabel(), tvp);
 		}
 	}
 }
 


The target producer is:
Code:
 public class Chemtest2Producer implements 
 	ViewComponentProducer, 
 	ViewParamsReporter,
 	ViewParamsReceiver
 {
 	Map mapparams = new HashMap();
 	
 	public String getViewID() {
 		return "chemtest2";
 	}
 
 	public void fillComponents(UIContainer arg0, ViewParameters arg1, ComponentChecker arg2) {
 		UIOutput.make(arg0, "test", "Testing again: " + mapparams.size() + " THE END");
 	}
 
 	public ViewParameters getViewParameters() {
 		return new TopicViewParameters();
 	}
 
 	public void setViewParamsExemplar(String arg0, ViewParameters arg1) {
 		System.out.println("SWG: Chemtest2.setViewParamsExemplar");
 	}
 
 	public void setViewParametersMap(Map arg0) {
 		System.out.println("SWG: Chemtest2.setViewParametersMap");
 		mapparams = arg0;
 	}
 
 	public void setDefaultView(String arg0) {
 		System.out.println("SWG: Chemtest2.setDefaultView");
 	}
 
 }
 


As you can see, I'm confused as to how I get the parameter value in the second producer. I can see on the link in the page that it's getting encoded as chemtest2?rdfuri=topicuri.

Are the ViewParameters/Parameters supposed to be getting injected somehow?

Thanks!
[WWW]
antranig
Request-scope Wrangler

Joined: 03/04/2006 13:29:55
Messages: 643
Offline

OK, the problem here is that ViewParametersReceiver is generally irrelevant to users, it's internal framework stuff that you shouldn't need to deal with at first (*)

The ViewParameters you're looking for are actually the 2nd argument to Chemtest2Producer - by returning the right type from getViewParameters you guarantee that you can cast these to TopicViewParameters.

I thought for a while about making a "request-scope" version of this "interface" so you could do without the cast (i.e. you could just make a setTopViewParameters(TopicViewParameters viewparams), but in general I'm worrying about the costs of having too many request-scope things these days. I guess given the choice most people would use the cast rather than pay 10 microseconds for a bean...



(*) ViewParamsReceiver is actually used by the main families of ViewProducers (e.g. XML-based and Java-based) to ferry the expected ViewParameter types back and forth)
stevegithens
Request-scope Wrangler

Joined: 04/04/2006 20:34:52
Messages: 84
Location: ooeepooee
Offline

Sooo... at one point last week, I had my Custom ViewParameteters working, but over the course of a few days I managed to have none of them working.

In the fillComponents, I continually get a ClassCastException because it thinks its getting a SimpleViewParameters. However, the rendered HTML does show the 'sortby' parameter.

Here is the code for the Producer and custom ViewParameters:

Code:
 public class SortingtableProducer implements ViewComponentProducer {
 
 	class LingualNumber
 	{
 		int num;
 		String english, japanese, spanish;
 		
 		public LingualNumber(int n, String e, String j, String s)
 		{
 			num = n; english = e; japanese = j; spanish = s;
 		}
 	}
 	
 	class LNComp implements Comparator
 	{
 		public LNComp(int sortby) { this.sortby = sortby; }
 		
 		int sortby = 0; // 0=num, 1=english, 2=japanese, 3=spanish
 		public int compare(Object o1, Object o2) {
 			LingualNumber n1 = (LingualNumber) o1; 
 			LingualNumber n2 = (LingualNumber) o2;
 			
 			switch (sortby) {
 			case 1: 
 				return n1.english.compareTo(n2.english);
 			case 2:
 				return n1.japanese.compareTo(n2.japanese);
 			case 3:
 				return n1.spanish.compareTo(n2.spanish);
 			default: 
 				if (n1.num < n2.num) return -1;
 				else if (n1.num > n2.num) return 1;
 				else return 0;
 			}
 		}	
 	}
 	
 	
 	public String getViewID() {
 		return "sortingtable";
 	}
 
 	public void fillComponents(UIContainer arg0, ViewParameters arg1, ComponentChecker arg2) {
 		int sortby = 0;
 		try {
 			SortingtableParams stp = (SortingtableParams) arg1;
 			sortby = Integer.parseInt(stp.sortby);
 		}
 		catch (Exception e)
 		{
 			System.out.println("SWG: SortingtableParams Ex");
 			e.printStackTrace();
 		}
 		
 		ArrayList list = new ArrayList();
 		
 		list.add(new LingualNumber(1, "one", "ichi", "uno"));
 		list.add(new LingualNumber(2, "two", "ni", "dos"));
 		list.add(new LingualNumber(3, "three", "san", "tres"));
 		list.add(new LingualNumber(4, "four", "shi", "quatro"));
 		
 		Collections.sort(list, new LNComp(sortby));
 		
 		
 		UIBranchContainer h1 = UIBranchContainer.make(arg0,"headerrow:");
 		SortingtableParams stp = new SortingtableParams();
 		stp.sortby = "0";
 		stp.viewID = "sortingtable";
 		UIInternalLink.make(h1, "collink", "Num", stp);
 		
 		UIBranchContainer h2 = UIBranchContainer.make(arg0,"headerrow:");
 		SortingtableParams stp2 = new SortingtableParams();
 		stp2.sortby = "1";
 		stp2.viewID = "sortingtable";
 		UIInternalLink.make(h2, "collink", "English", stp2);
 		
 		UIBranchContainer h3 = UIBranchContainer.make(arg0,"headerrow:");
 		SortingtableParams stp3 = new SortingtableParams();
 		stp3.sortby = "2";
 		stp3.viewID = "sortingtable";
 		UIInternalLink.make(h3, "collink", "Japanese", stp3);
 		
 		UIBranchContainer h4 = UIBranchContainer.make(arg0,"headerrow:");
 		SortingtableParams stp4 = new SortingtableParams();
 		stp4.sortby = "3";
 		stp4.viewID = "sortingtable";
 		UIInternalLink.make(h4, "collink", "Spanish", stp4);
 	
 		
 		for (int i = 0; i < list.size(); i++)
 		{
 			LingualNumber n = (LingualNumber) list.get(i);
 			UIBranchContainer b = UIBranchContainer.make(arg0,"tablerow:");
 			UIOutput.make(b, "integers", Integer.toString(n.num));
 			UIOutput.make(b, "english", n.english);
 			UIOutput.make(b, "japanese", n.japanese);
 			UIOutput.make(b, "spanish", n.spanish);
 		}
 		
 		
 	}
 
 	public SortingtableParams getViewParameters()
 	{
 		SortingtableParams stp = new SortingtableParams();
 		stp.viewID = "sortingtable";
 		stp.sortby = "0";
 		return stp;
 	}
 	
 	public SortingtableParams getViewParameter()
 	{
 		SortingtableParams stp = new SortingtableParams();
 		stp.viewID = "sortingtable";
 		stp.sortby = "0";
 		return stp;
 	}
 	
 }
 


Code:
 public class SortingtableParams extends SimpleViewParameters {
 	public String sortby;
 	public StringList getAttributeFields()
 	{
 		StringList togo = super.getAttributeFields().copy();
 		togo.add("sortby");
 		return togo;
 	}
 	
 	public ViewParameters copyBase()
 	{
 		SortingtableParams togo = (SortingtableParams)super.copyBase();
 		togo.sortby = sortby;
 		return togo;
 	}
 }
 


Code:
 <html>
 <head>
 <title>RSF Number Guessing Application - Index</title>
 <link rel="stylesheet" rsf:id="scr=rewrite-url" href="../style.css" type="text/css"/>
 <link href="/library/skin/tool_base.css" type="text/css" rel="stylesheet" media="all"/>
 <link href="/library/skin/default/tool.css" type="text/css" rel="stylesheet" media="all"/>
 <script type="text/javascript" language="JavaScript" src="/library/js/headscripts.js"></script>
 </head>
 <body rsf:id="scr=sakai-body">
 <div class="portletBody">
 <!-- <form rsf:id="basic-form"> -->
 <h1>Sorting Table</h1>    
 
 <table>
 	<thead>
 	<tr>
 		<td rsf:id="headerrow:"><a href="" rsf:id="collink">Num</a></td>
 		<td rsf:id="headerrow:"><a href="" rsf:id="collink">English</a></td>
 		<td rsf:id="headerrow:"><a href="" rsf:id="collink">Japanese</a></td>
 		<td rsf:id="headerrow:"><a href="" rsf:id="collink">Spanish</a></td>
 	</tr>
 	</thead>
 	<tr rsf:id="tablerow:">
 		<td rsf:id="integers">1</td>
 		<td rsf:id="english">one</td>
 		<td rsf:id="japanese">ichi</td>
 		<td rsf:id="spanish">uno</td>
 	</tr>
 	<tr rsf:id="tablerow:">
 		<td rsf:id="integers">2</td>
 		<td rsf:id="english">two</td>
 		<td rsf:id="japanese">ni</td>
 		<td rsf:id="spanish">dos</td>
 	</tr>
 	<tr rsf:id="tablerow:">
 		<td rsf:id="integers">3</td>
 		<td rsf:id="english">three</td>
 		<td rsf:id="japanese">san</td>
 		<td rsf:id="spanish">tres</td>
 	</tr>
 </table>
 
 <!-- </form> -->
 </div>
 </body>
 </html>
 


Suggestions? Thanks.
[WWW]
antranig
Request-scope Wrangler

Joined: 03/04/2006 13:29:55
Messages: 643
Offline

You forgot to implement the ViewParamsReporter interface in your ViewProducer.
 
Forum Index -> RSF Help and Problems
Message Quick Reply
Go to:   
Powered by JForum 2.1.6 © JForum Team