To learn more on these subjects... |
|---|
| portlet |
| HTML |
| XML |
| HTML Cascading Style Sheets |
|
Cascading Style Sheet standard, as defined
by W3 consortium Which styles your favorite browser knows... A tutorial... |
With these preliminaries, we are going to start coding a very simple portlet that will display a picture.
Our first portlet, the PhotoPortlet will display a picture in a frame.
We want to allow the user to give the name of a graphic file, enter dimensions,
and eventually a title.
PhotoPortlet.java that contains the PhotoPortlet class.
CLASSPATH environment variable to include the root
of the directories arborescence (below tv) that you've just created.
PhotoPortlet.java file in the photo
directory.
We are going to comment the details of our first portlet code.
PhotoPortlet doesn't
go against that rule.
Our class belongs to the tv.alterna.pp.photo package. That's good practice to put all the files that compose a portlet in a separate package, but you don't need to name it with a tv.alterna.pp prefix.
package tv.alterna.pp.photo;Then, we must list all imports. The first block references the base classes from the PersonalPortal
import tv.alterna.pp.PersonalPortal; import tv.alterna.pp.PersonalPortlet; import tv.alterna.pp.PageRequest; import tv.alterna.pp.PortalConfig; import tv.alterna.pp.StyleSheet; import tv.alterna.pp.Style; import tv.alterna.pp.StyleProperty; import tv.alterna.pp.PortalUtil; import tv.alterna.utils.HtmlUtil; import java.util.Iterator;As our portlet will save and load its configuration in a file, it needs at least how to do it.
import java.io.PrintWriter; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.InputStream; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException;Then, we will format configuration files with XML, and the XML Digester is here to help us it the task.
import org.apache.struts.digester.Digester; import org.xml.sax.SAXException;
PhotoPortlet.java file,
the class will be name, to be really original, PhotoPortlet!
PersonalPortlet
class that defines their default behavior and the contracts they must follow.
/**
* The Photo portlet is a very simple portlet to display a picture in a frame.
*
* @author GenePi
* @created 19 mars 2001
*/
public class PhotoPortlet
extends PersonalPortlet
{
Portlet class are declared with access control public
to let the portal create instances when the user put a portlet of that type on his
page.
PhotoPortlet object
that a user put on his portal page.
/** * The file name of the picture. */ private String _fileName = ""; /** * The width of the picture */ private String _width = ""; /** * The height of the picture */ private String _height = "";We don't have defined a
_title atribute
to store the picture title. In fact, this attribute is already defined for
every portlet in the class PersonalPortlet.
setAttribut()) and another to read it (getAttribut()).
/**
* Set the name of the picture file.
*
* @param fileName The file name.
*/
public void setFileName(final String fileName)
{
_fileName = (fileName == null) ? "" : fileName;
}
We don't store the null value into
String attributes, but we replace it with the empty string "".
This make the display of the attribute simpler when the portlet is displayed
in configuration mode.
/**
* Set the width of the picture.
*
* @param width The width of the picture.
*/
public void setWidth(final String width)
{
_width = (width == null) ? "" : width;
}
/**
* Set the height of the picture.
*
* @param height The height of the picture.
*/
public void setHeight(final String height)
{
_height = (height == null) ? "" : height;
}
/**
* Obtain the name of the file containing the picture.
*
* The file name can be either:
* - a URL http://...
* - an absolute path file://...
* - a relative path to the base of the portal
*
* @return The file name
*/
protected String getFileName()
{
return _fileName;
}
The picture file name can be, a Web URL (of the form
http://www.asite...), or a local URL (of the form
file:///C:/My Documents/...), or else a path relative to the portal
base. The portal base determines the directory from which the
Pepo looks for the resources, and can be changed
in the GeneralPortlet with all other portal options.
/**
* Obtain the width of the picture.
*
* @return The width in pixels
*/
protected String getWidth()
{
return _width;
}
/**
* Obtain the height of the picture.
*
* @return The height in pixels
*/
protected String getHeight()
{
return _height;
}
All access methods that can be called from another package,
and in particular from the portal engine or the XML Digester, must be defined
with public access control..
PersonalPortlet class:
PersonalPortlet.DISPLAY: Used when displaying the
portlet data, here the picture.
PersonalPortlet.LAYOUT: When the user put the portlet
on his portal page.
PersonalPortlet.PARAM: In configuration mode and the
user type in the parameters of the portlet, here the picture file, dimensions
and title.
String getDisplayHTML(final PageRequest request)
String getLayoutHTML(final PageRequest request)
String getParameterHTML(final PageRequest request)
PersonalPortlet class has a default implementation of
getLayoutHTML that only displays the title of the portlet. But
you must define the other two methods.
Let's start with getDisplayHTML.
The objective of this method is to display a picture in a frame. To achieve that,
we will use the HTML tag <img>. To create the frame, and to avoid
that the portlet encroach upon the other components of the portal page, we will
insert the generated HTML code into a table (tag <table>).
We will define two styles:
photoPortlet: applyed to the whole table that contains the picture.
photoTitle: for the photo title.
<table class="photoPortlet">
<tr>
<td>
<img src="MyPicture.jpg" border="0" alt="My picture">
</td>
</tr>
<tr>
<td class="photoTitle">
My picture
</td>
</tr>
</table>
Let's go...
/**
* Generate the HTML code used to display the data.
*
* @param request The request.
* @return The HTML used to display the data.
*/
protected String getDisplayHTML(final PageRequest request)
{
StringBuffer buf = new StringBuffer();
We check first that we know the file name of the
picture. If we don't, we display an error message with the system style
error.
// Check that we have all needed information
if (getFileName() == null || "".equals(getFileName()))
{
final String msgError = HtmlUtil.encode(getMessage("getDisplayHTML.error.fileMissing"));
buf.append("<table class=\"photoPortlet\"><tr><td class=\"error\">");
buf.append(msgError);
buf.append("</td></tr></table>");
return buf.toString();
}
Then we can start to generate the HTML code.
If the picture file name is a URL, then we can use it as source in the tag
<img>. Else, we consider it's a relative path and we must
concatenate it with the portal base.
buf.append("<table class=\"photoPortlet\"><tr><td>");
buf.append("<img src=\"");
buf.append(HtmlUtil.encodeURI(PortalUtil.addBase(getFileName())));
buf.append("\" border=\"0\"");
If the user has typed the image size, we take it into
account to display the picture.
if (getWidth() != null && !"".equals(getWidth()))
{
buf.append(" width=\"");
buf.append(getWidth());
buf.append("\"");
}
if (getHeight() != null && !"".equals(getHeight()))
{
buf.append(" height=\"");
buf.append(getHeight());
buf.append("\"");
}
buf.append(" alt=\"");
buf.append(getTitle());
buf.append("\">");
If the picture has a title, we add a new row to the table
and put the title there, that will be displayed under the photo.
if (getTitle() != null && !"".equals(getTitle()))
{
buf.append("</td></tr><tr><td class=\"photoTitle\">");
buf.append(getTitle());
}
buf.append("</td></tr></table>\n");
return buf.toString();
}
getDisplayHTML()getMessage() method, defined into the PersonalPortlet class,
can find a message in the language selected by the user. You, as author, have the
responsability to put the messages in the supported languages into the resource
files. This method has orther overloaded variants with a variable number of
arguments..properties.
The HtmlUtil.encode() methods filters sensitive characters from
the message and replace them with HTML entities. That way, you don't need to know
if your messages contains characters like <, >, & or even accentuated
ones.
Creating the resource files for our example:
PhotoPortlet_fr.properties file and save it into the
init directory.
# PhotoPortlet - Messages en français ##################################### getDisplayHTML.error.fileMissing=Le nom du fichier image n''a pas été renseigné. getParameterHTML.title=Titre de la photo getParameterHTML.help=Saisissez le nom d''un fichier graphique et indiquez les \ dimensions de l''image si vous désirez la redimensionner. Vous pouvez saisir \ une URL, un chemin absolu ou relatif par rapport à la base de Pepo.\n Pour changer la présentation du cadre de la photo, utilisez le portlet \ Gestionnaire de Styles. getParameterHTML.fileName=Nom du fichier contenant l''image getParameterHTML.width=Largeur de l''image en pixels getParameterHTML.height=Hauteur de l''image en pixels # Styles ######## style.photoPortlet=Cadre de la photo style.photoTitle=Titre de la photo
PhotoPortlet_en.properties file and save it into the
init directory too.
# PhotoPortlet - English messages ################################# getDisplayHTML.error.fileMissing=The file name of the picture is missing and \ can''t be displayed. getParameterHTML.title=Title of the photo getParameterHTML.help=Type the name of a graphic file and input the width and \ height of the picture if you want to resize it. You can type an URL, an absolute \ path file or relative to Pepo base.\nTo change the appearance of \ theframe of the picture, use the Styles Manager portlet. getParameterHTML.fileName=Name of the picture file getParameterHTML.width=Width of the picture, in pixels getParameterHTML.height=Height of the picture, in pixels # Styles ######## style.photoPortlet=Frame of the picture style.photoTitle=Title of the picture
getParameterHTML() method has the responsability to generate
the corresponding HTML code.
<form method="get" action="/admin/Photos/">
<input type="hidden" name="id" value="28">
<table class="portlet">
<tr>
<td class="portletTitle" colspan="2">Photo - My Picture</td>
</tr>
<tr>
<td class="portletHelp" colspan="2">Type the name
of a graphic file and input the width and height of the picture if you want
to resize it. You can type an URL, an absolute path file or relative to
Pepo base.<br>To change the appearance of the frame of the
picture, use the Styles Manager portlet.</td>
</tr>
<tr>
<td class="label">Title of the photo</td>
<td class="value"><input type="text" class="value" name="title" size="30" value="My Picture"></td>
</tr>
<tr>
<td class="labelMandatory">Name of the picture file</td>
<td class="valueMandatory"><input type="text" class="valueMandatory" name="fileName" size="30" value="img/MyPicture.jpg"></td>
</tr>
<tr>
<td class="label">Width of the picture, in pixels</td>
<td class="value"><input type="text" class="value" name="width" maxlength="5" size="5" value=""></td>
</tr>
<tr>
<td class="label">Height of the picture, in pixels</td>
<td class="value"><input type="text" class="value" name="height" maxlength="5" size="5" value=""></td>
</tr>
<tr class="action">
<td class="action" colspan="2"><input type="submit" name="generalSubmit" class="submit" value="Submit">
<input type="reset" name="generalReset" class="reset" value="Reset"></td>
</tr>
</table>
</form>
/**
* Generate the HTML code used in parameter input mode.
*
* If the portlet has to process a form, it must include its
* <code>id</code> in the parameters in order to receive the request
* when the user submit the form.
*
* @param request The request.
* @return The HTML code to input paramters.
*/
protected String getParameterHTML(final PageRequest request)
{
Messages displayed to the user are retrieved from
resource files.
final String msgTitle = HtmlUtil.encode(getMessage("getParameterHTML.title"));
final String msgHelp = HtmlUtil.encode(getMessage("getParameterHTML.help"));
final String msgFileName = HtmlUtil.encode(getMessage("getParameterHTML.fileName"));
final String msgWidth = HtmlUtil.encode(getMessage("getParameterHTML.width"));
final String msgHeight = HtmlUtil.encode(getMessage("getParameterHTML.height"));
final String msgSubmit = HtmlUtil.encode(getMessage("button.submit"));
final String msgReset = HtmlUtil.encode(getMessage("button.reset"));
StringBuffer buf = new StringBuffer();
In order for the portlet to receive the user input,
it must tell the portal that it is interested in treating the request. It can
do that with the method boolean PersonalPortlet.hasInterest(PageRequest request).
The default implementation of that method sends the request to the portlet
whose identifier is given as a request parameter. That's the reason why we
define a hidden field that contains the portlet identifier, obtained with a
call to getId().
// Form
buf.append("<form method=\"get\" action=\"");
buf.append(request.getAction());
buf.append("\">\n");
buf.append("<input type=\"hidden\" name=\"id\" value=\"");
buf.append(getId());
buf.append("\">\n");
buf.append("<table class=\"portlet\"><tr><td class=\"portletTitle\" colspan=\"2\">");
buf.append(getHTMLIconHelp("help"));
buf.append("Photo - ");
buf.append(getTitle());
buf.append("</td></tr>\n<tr><td class=\"portletHelp\" colspan=\"2\">");
buf.append(msgHelp);
buf.append("</td></tr>\n<tr><td class=\"label\">");
buf.append(msgTitle);
buf.append("</td><td class=\"value\"><input type=\"text\" class=\"value\" name=\"title\" size=\"30\" value=\"");
buf.append(getTitle());
buf.append("\"></td></tr>\n<tr><td class=\"labelMandatory\">");
buf.append(msgFileName);
buf.append("</td><td class=\"valueMandatory\"><input type=\"text\" class=\"valueMandatory\" name=\"fileName\" size=\"30\" value=\"");
buf.append(getFileName());
buf.append("\"></td></tr>\n<tr><td class=\"label\">");
buf.append(msgWidth);
buf.append("</td><td class=\"value\"><input type=\"text\" class=\"value\" name=\"width\" maxlength=\"5\" size=\"5\" value=\"");
buf.append(getWidth());
buf.append("\"></td></tr>\n<tr><td class=\"label\">");
buf.append(msgHeight);
buf.append("</td><td class=\"value\"><input type=\"text\" class=\"value\" name=\"height\" maxlength=\"5\" size=\"5\" value=\"");
buf.append(getHeight());
buf.append("\"></td></tr>\n");
// Action buttons
buf.append("<tr class=\"action\"><td class=\"action\" colspan=\"2\">");
buf.append("<input type=\"submit\" name=\"generalSubmit\" class=\"submit\" value=\"");
buf.append(msgSubmit);
buf.append("\"> ");
buf.append("<input type=\"reset\" name=\"generalReset\" class=\"reset\" value=\"");
buf.append(msgReset);
buf.append("\"></td></tr>\n");
buf.append("</table>\n");
buf.append("</form>");
return buf.toString();
}
When the portlet creates code for the display modes
PersonalPortlet.LAYOUT or PersonalPortlet.PARAM,
that's to say in the methods getLayoutHTML() and getParameterHTML(),
you must not use the portlet style sheet but the system one instead. This is done
to guarantee that all the portlets have the same look in that mode.
PersonalPortlet class defines the method below to do these operations:
void processParameterForm(PageRequest request)
void processLayoutForm(PageRequest request)
void processDisplayForm(PageRequest request)
PersonalPortlet.hasInterest(int mode, PageRequest request)
method and return the value true to be called back. To make
the development of portlets simpler, the default definition of hasInterest()
considers that a portlet is interested in receiving a request if there's a parameter
named id whose value is the portlet identifier.id in the portlet
input form. We don't have anything more to do to process the user input...
/**
* Process the input from the parameters form.
* Save the name of the file containing the picture, and other
* information.
*
* @param request The request.
* @see PersonalPortlet#hasInterest
*/
protected void processParameterForm(final PageRequest request)
{
String fileName = request.getParameterValue("fileName");
setFileName(fileName);
String title = request.getParameterValue("title");
setTitle(title);
String width = request.getParameterValue("width");
setWidth(width);
String height = request.getParameterValue("height");
setHeight(height);
}
This method only extracts values from the request parameters
and store them in the portlet attributes.
/**
* Request to save the state of the portlet.
* The configuration is usually written as an XML file.
*
* @exception IOException An exception occured while saving the state
* of the portlet.
*/
protected void saveConfig()
throws IOException
{
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(getConfigFile() + getId() + ".xml")));
This procedure only opens a PrintWriter
and write the portlet content into.PhotoPortletY.xml,
where Y is the portlet identifier. The file name prefix is obtained
with a call to PersonalPortlet.getConfigFile().
out.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
out.println();
out.println("<!-- PhotoPortlet Configuration file -->");
out.println("<!-- =============================== -->");
out.println();
out.println("<photoPortlet>");
saveConfig(out);
out.println("</photoPortlet>");
out.flush();
out.close();
}
saveConfig() and loadConfig
methods are automatically called by the portal when the user want to save the
configuration, or when he starts the portal and all the portlets are initialized
(or when he adds a new portlet to a page).
<!-- PhotoPortlet Configuration file --> <!-- =============================== --> <photoPortlet> <!-- Title of the photo or picture --> <title>MaPhoto</title> <!-- Name of the file containing the picture --> <fileName>img/MaPhoto.jpg</fileName> <!-- Width of the picture, in pixels or percent --> <width></width> <!-- Height of the picture, in pixels or percent --> <height></height> </photoPortlet>Remember that the XML syntax distinguishes between upper and lower case. So,
<photoPortlet> is different from
<PhotoPortlet>. You can check that your XML file is well
balanced if you can open it with Microsoft Internet Explorer: that browser
can read XML files and will print a message if it detects an error.
We have to handle two XML configuration files:
PhotoPortlet.xml: contains
default values used when creating a new PhotoPortlet object. That
file contains the styles used by all portlet of the PhotoPortlet type.
PhotoPortletY.xml: contains the parameters for the
portlet identified by Y. The portlet identifier is automatically assigned
by the portal when a new portlet is created.
init directory.
PhotoPortlet object.loadConfig() method is called when the portal is started and
portlet instances are loaded, or when the user add a new PhotoPortlet
on a page. In the first case, initialization data is found into init/PhotoPortletY.xml,
and in the second case into init/PhotoPortlet.xml.
/**
* Request to read the portlet configuration file and set the
* portlet state. We try first to read the configuration from the
* file "PhotoPortlet{id}.xml", and if not found from "PhotoPortlet.xml".
*
* @param fileName The name of the configuration file.
* @exception IOException A problem occured while loading the
* portlet configuration.
*/
protected void loadConfig(final String fileName)
throws IOException
{
PersonalPortal.log(2, "Loading configuration of portlet: " + this);
// Load the config
InputStream in = null;
try
{
in = new BufferedInputStream(new FileInputStream(fileName));
We use the XML Digester to read and interpret an XML
file. It parses the file content and call the methods we specify when it matches
patterns in the input file.Digester object that parses XML files without validation
(we don't have defined an XML grammar) and we make it communicate with the portlet
(digester.push(this)).
Digester digester = new Digester(); digester.push(this); digester.setDebug(PersonalPortal.getDebug() - 1); digester.setValidating(false);When the XML input stream matches the tag
<title> inside a tag
<photoPortlet>,
we tell the Digester to call the setTitle() method with the
<title> content as parameter.
// Configuration of the portlet
digester.addCallMethod("photoPortlet/title", "setTitle", 0);
We continue with the Digester rules to call the corresponding
methods when we encounter the following tags <fileName>,
<width> and
<height; in the XML input stream.
digester.addCallMethod("photoPortlet/fileName", "setFileName", 0);
digester.addCallMethod("photoPortlet/width", "setWidth", 0);
digester.addCallMethod("photoPortlet/height", "setHeight", 0);
The last step is to call the parse method
to have the digester process the XML file and initialize the PhotoPortlet instance
with the read values.
digester.parse(in);
}
catch (IOException ioe)
{
PersonalPortal.log(0, "I/O error while reading PhotoPortlet configuration file. reason: " + ioe.getMessage());
}
catch (SAXException se)
{
PersonalPortal.log(0, "Error in the PhotoPortlet configuration file. reason: " + se.getMessage());
}
finally
{
if (in != null)
{
in.close();
}
}
}
photoPortlet and
photoTitle.PhotoPortlet portlets on a user page,
it needs to access the style definitions. As we say before,
these styles are stores into the init/PhotoPortlet.xml file.
Here that file content:
<!-- PhotoPortlet Configuration file --> <!-- =============================== --> <photoPortlet> <!-- Title of the photo or picture --> <title>Ma Photo</title> <!-- Name of the file containing the picture --> <fileName>img/MaPhoto.jpg</fileName> <!-- Width of the picture, in pixels or percent --> <width></width> <!-- Height of the picture, in pixels or percent --> <height></height> <!-- Style sheet used by the PhotoPortlet --> <styles> <style name=".photoTitle" description="style.photoTitle"> <property name="font-family" value="Arial, Helvetica, sans-serif" /> <property name="font-size" value="12px" /> <property name="font-variant" value="small-caps" /> <property name="font-weight" value="bold" /> <property name="text-align" value="center" /> <property name="color" value="yellow" /> </style> <style name=".photoPortlet" description="style.photoPortlet"> <property name="border-width" value="10" /> <property name="border-color" value="gold" /> <property name="background-color" value="goldenrod" /> <property name="border-style" value="outset" /> </style> </styles> </photoPortlet>
loadStyleSheet() and saveStyleSheet() methods when the
portlet needs to load or save its style sheet.
/**
* Request to load the styles sheet to render the portlet as HTML.
*
* @exception IOException A problem occured while loading the portlet
* style sheet.
*/
protected void loadStyleSheet()
throws IOException
{
Each portlet is called back to load the style sheet that
it uses. Though, the style sheet is frequently shared between all portlets of the
same type (PortletDefinition) that will be displayed in the same way.StyleSheet.loadStyleSheet() with parameters the directory where to
find the file and the matching patterns
(<styles> tags inside of <photoPortlet> tag).
// Loading the style sheet associated with that portlet, if necessary
StyleSheet styleSheet = getDefinition().getStyleSheet();
if (styleSheet == null)
{
styleSheet = StyleSheet.loadStyleSheet(getConfigFile() + ".xml", "photoPortlet");
If we can't load the style sheet, we decide to
create a new file with default values.
if (styleSheet == null)
{
styleSheet = new StyleSheet();
Style style = new Style(".photoPortlet", "style.photoPortlet");
style.addProperty(new StyleProperty("border-style", "outset"));
style.addProperty(new StyleProperty("border-color", "gold"));
style.addProperty(new StyleProperty("border-width", "10"));
style.addProperty(new StyleProperty("background-color", "goldenrod"));
styleSheet.addStyle(style);
style = new Style(".photoTitle", "style.photoTitle");
style.addProperty(new StyleProperty("font-family", "Arial, Helvetica, sans-serif"));
style.addProperty(new StyleProperty("color", "yellow"));
style.addProperty(new StyleProperty("font-size", "12px"));
style.addProperty(new StyleProperty("font-variant", "small-caps"));
style.addProperty(new StyleProperty("font-weight", "bold"));
style.addProperty(new StyleProperty("text-align", "center"));
styleSheet.addStyle(style);
}
We associate the style sheet with the PhotoPortlet
portlet type.
getDefinition().setStyleSheet(styleSheet); } }
saveStyleSheet() method.init/PhotoPortlet.xml file its attributes
values, followed by the style sheet properties. If the user has many instances
of that type of portlet, they will all write into the same file: the attribute values
of the last portlet instance will be used as default values. We could have defined
other algorithms, but this one is definitively the simplest.
/**
* Request to save the style sheet associated with that portlet (or
* common to all the portlets with the same portlet definition).
*
* @exception IOException If a problem occurs while saving the styles.
*/
protected void saveStyleSheet()
throws IOException
{
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(getConfigFile() + ".xml")));
out.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
out.println();
out.println("<!-- PhotoPortlet Configuration file -->");
out.println("<!-- =============================== -->");
out.println();
out.println("<photoPortlet>");
Save the portlet attributes.
// The configuration of the portlet, as example saveConfig(out);Save the style sheet associated with the portlet type. The
StyleSheet.getXMLConfig() is call with a indent level
parameter to keep the XML file correctly indented.
// The styles
out.println("\n\n\t<!--");
out.println("\t Style sheet used by the PhotoPortlet");
out.println("\t-->");
StyleSheet styleSheet = getDefinition().getStyleSheet();
if (styleSheet != null)
{
out.println(styleSheet.getXMLConfig(1));
}
out.println("</photoPortlet>");
out.flush();
out.close();
}
The saveConfig method, already used in
previous methods, actually save the portlet attributes.
/**
* Save the state of the PhotoPortlet on the writer.
*
* @param out The writer where to save the configuration of the portlet.
* @exception IOException If an IO error occurs.
*/
private void saveConfig(final PrintWriter out)
throws IOException
{
out.println("\t<!-- Title of the photo or picture -->");
if (getTitle() == null)
out.print("\t<title>");
out.print(getTitle());
out.println("</title>");
out.println("\t<!-- Name of the file containing the picture -->");
out.print("\t<fileName>");
out.print(getFileName());
out.println("</fileName>");
out.println("\t<!-- Width of the picture, in pixels or percent -->");
out.print("\t<width>");
out.print(getWidth());
out.println("</width>");
out.println("\t<!-- Height of the picture, in pixels or percent -->");
out.print("\t<height>");
out.print(getHeight());
out.println("</height>");
}
getHTMLStylesExample() whose role is to generate HTML code showing
the styles used by the portlet. That method is called when the user changes the
style definitions for the portlet, as a visual feedback of modifications.PhotoPortlet
styles. If you choose not to redefine that method, the default implementation
print a warning message telling there's no style example.
/**
* Create an example demonstrating the use of the styles properties
* so that the user immediately see the impact of a style property
* change.
* Used to display an example in the StylesManager portlet.
*
* @param title The type of the portlet selected by the user, to
* appear in the title.
* @return The HTML code to create the example.
*/
protected String getHTMLStylesExample(final String title)
{
StringBuffer buf = new StringBuffer();
buf.append("<table class=\"photoPortlet\"><tr><td><img src=\"");
buf.append(HtmlUtil.encodeURI(PortalConfig.getBase()));
buf.append("img/PhotoPortlet.jpg\" border=\"0\"></td></tr>\n<tr><td class=\"photoTitle\">");
buf.append(HtmlUtil.encode(title));
buf.append("</td></tr></table>\n");
return buf.toString();
}
Copy a JPEG file named PhotoPortlet.jpg
into the img directory to serve as sample picture.
PhotoPortlet code to Pepoinit/PersonalPortal.xml file.init/PersonalPortal.xml with a file editor.
<portlets> section
<!-- List the portlets available. --> <!-- ============================ --> <!-- For each portlet definition, we have the attributes: - type: The type of the portlet. - description: The name that will be presented to the user to select the portlet in the portal. - className: The class of the portlet, used to load it if the user select it in his portal. - propertyFile: The base file name of the property file containing the localized messages for that type of portlet. --> <portlets> <definition type="mailPOP3" description="Courier POP3" className="tv.alterna.pp.mail.POP3Portlet" propertyFile="init/POP3Portlet" />We say that the portlet type is
photo
(the type name must be unique), that the portlet is defined by the Java class
tv.alterna.pp.photo.PhotoPortlet and where is located the configuration
file (init/PhotoPortlet). We also have to define a brief comment
describing the portlet, that will be displayed to the user when he wants to
select it and place a new instance on a portal page (Photo and picture).
<definition type="photo" description="Photo and picture" className="tv.alterna.pp.photo.PhotoPortlet" propertyFile="init/PhotoPortlet" />Lines were removed here...
</portlets>
PhotoPortlet.java file.
If you swith into the portal configuration mode, you will notice that a new portlet type is available Photo and picture that you can use to display a picture.
CLASSPATH environment variable allows the Java run time
to load the portlet class.
PersonalPortlet.log(niveau, message)
method, like the example. Debug messages are printed when the debug level of the
portla is superior to the method argument.java tv.alterna.pp.PersonalPortal debug=2
| Resource files and multilingual support |
|---|
| ResourceBundle |
| XML Digester |
| The Struts project from where originated the XML Digester |
| Other portlets |
| SnapshotTVPortlet |
| POP3Portlet |
| NewsPortlet |
| ToDoPortlet |