Seam SVN: r11427 - sandbox/trunk/modules/xwidgets/src/main/javascript.
by seam-commits@lists.jboss.org
Author: shane.bryzak(a)jboss.com
Date: 2009-08-25 22:34:26 -0400 (Tue, 25 Aug 2009)
New Revision: 11427
Modified:
sandbox/trunk/modules/xwidgets/src/main/javascript/xw.Panel.js
sandbox/trunk/modules/xwidgets/src/main/javascript/xw.js
Log:
groundwork for layout management
Modified: sandbox/trunk/modules/xwidgets/src/main/javascript/xw.Panel.js
===================================================================
--- sandbox/trunk/modules/xwidgets/src/main/javascript/xw.Panel.js 2009-08-25 20:00:55 UTC (rev 11426)
+++ sandbox/trunk/modules/xwidgets/src/main/javascript/xw.Panel.js 2009-08-26 02:34:26 UTC (rev 11427)
@@ -5,11 +5,27 @@
this.width = 200;
this.height = 100;
this.parent = null;
- this.control = null;
+ this.control = null;
+ this.align = null;
xw.controls.Panel.prototype.setParent = function(parent)
{
this.parent = parent;
+ }
+
+ xw.controls.Panel.prototype.setAlign = function(align)
+ {
+ this.align = align;
+ }
+
+ xw.controls.Panel.prototype.setWidth = function(width)
+ {
+ this.width = width;
+ }
+
+ xw.controls.Panel.prototype.setHeight = function(height)
+ {
+ this.height = height;
}
xw.controls.Panel.prototype.paint = function()
@@ -19,10 +35,32 @@
this.control = document.createElement("div");
this.control.widget = this;
this.parent.control.appendChild(this.control);
-
- this.control.style.width = "400";
- this.control.style.height = "200";
-
+
+ if (this.align == "top")
+ {
+ this.control.style.float = "top";
+ this.control.style.height = this.height;
+ }
+ else if (this.align = "bottom")
+ {
+ this.control.style.float = "bottom";
+ this.control.style.height = this.height;
+ }
+ else if (this.align = "left")
+ {
+ this.control.style.float = "left";
+ this.control.style.width = this.width;
+ }
+ else if (this.align = "right")
+ {
+ this.control.style.float = "right";
+ this.control.style.width = this.width;
+ }
+ else if (this.align = "client")
+ {
+ this.control.style.height = "100%";
+ }
+
this.control.style.backgroundColor = "#ece9d6";
this.control.style.borderTop = "1px solid white";
this.control.style.borderLeft = "1px solid white";
Modified: sandbox/trunk/modules/xwidgets/src/main/javascript/xw.js
===================================================================
--- sandbox/trunk/modules/xwidgets/src/main/javascript/xw.js 2009-08-25 20:00:55 UTC (rev 11426)
+++ sandbox/trunk/modules/xwidgets/src/main/javascript/xw.js 2009-08-26 02:34:26 UTC (rev 11427)
@@ -246,9 +246,8 @@
}
else
{
- // TODO improve this
var controlName = xw.Sys.capitalize(tag);
- var control = eval("new xw.controls." + controlName + "()");
+ var control = new xw.controls[controlName]();
control.parent = parentControl;
if (xw.Sys.isUndefined(parentControl.children))
@@ -388,7 +387,26 @@
return eval(this.script);
}
}
-}
+}
+
+/** LAYOUT MANAGERS **/
+
+xw.BorderLayout = function(container)
+{
+ this.container = container;
+
+ xw.BorderLayout.prototype.layout = function()
+ {
+ for (var i = 0; i < container.children.length; i++)
+ {
+ container.children[i].paint();
+ }
+ }
+
+}
+
+xw.layoutManagers = new Object();
+xw.layoutManagers["border"] = xw.BorderLayout;
/**
* A single instance of a view
@@ -396,16 +414,46 @@
xw.View = function()
{
this.container = null;
- this.children = new Array();
+ this.children = new Array();
+
+ this.layout = "border"; // The default layout
+ this.layoutManager = null;
+
+ /**
+ * Callback for window resize events
+ */
+ xw.View.prototype.resize = function()
+ {
+ // bubble the resize event through the component tree
+ }
+
+ xw.View.prototype.setLayout = function(layout)
+ {
+ this.layout = layout;
+ }
+
+ xw.View.prototype.setLayoutManager = function(layoutManager)
+ {
+ this.layout = null;
+ this.layoutManager = layoutManager;
+ }
xw.View.prototype.paint = function()
- {
- this.control = xw.Sys.getObject(this.container);
-
- for (var i = 0; i < this.children.length; i++)
- {
- this.children[i].paint();
- }
+ {
+ // Determine the container control
+ if ("string" == (typeof this.container))
+ this.control = xw.Sys.getObject(this.container);
+ else
+ this.control = this.container;
+
+ // Set the window resize callback so that we can respond to resize events
+ var target = this;
+ var callback = function() { target.resize(); };
+ xw.Sys.chainEvent(window, "resize", callback);
+
+ // Layout the child controls
+ if (this.layout != null) this.layoutManager = new xw.layoutManagers[this.layout](this);
+ this.layoutManager.layout();
}
}
@@ -429,4 +477,4 @@
xw.getResourceBase = function()
{
return xw.Sys.isUndefined(xw.resourceBase) ? "" : xw.resourceBase + "/";
-}
\ No newline at end of file
+}
15 years, 4 months
Seam SVN: r11426 - in branches/community/Seam_2_2/src/test/ftest: src/main/org/jboss/seam/example/common/test/selenium and 1 other directory.
by seam-commits@lists.jboss.org
Author: kpiwko(a)redhat.com
Date: 2009-08-25 16:00:55 -0400 (Tue, 25 Aug 2009)
New Revision: 11426
Added:
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeleniumDateSelector.java
Modified:
branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/GenerateEntitiesTest.java
branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/PersonTest.java
branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeamSelenium.java
Log:
JBQA-2276 selectDate() ftest method for Rich&IceFaces
Modified: branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/GenerateEntitiesTest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/GenerateEntitiesTest.java 2009-08-25 15:22:31 UTC (rev 11425)
+++ branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/GenerateEntitiesTest.java 2009-08-25 20:00:55 UTC (rev 11426)
@@ -24,10 +24,9 @@
import java.io.InputStream;
import java.util.Date;
+import org.jboss.seam.example.common.test.selenium.SeleniumDateSelector;
import org.testng.annotations.BeforeGroups;
-import com.thoughtworks.selenium.Wait;
-
/**
* This class and its subclasses test seam-gen's "generate-entities" feature.
* Every test method should be part of "generate-entitiesTest" in order to get
@@ -116,33 +115,28 @@
}
/**
- * Select a date using icefaces or richfaces calendar component. Selecting
- * hardcoded values is only implemented yet.
+ * Selects a date using icefaces or richfaces calendar component.
+ * @param date Date to be selected
*/
public void selectDate(Date date)
{
- // TODO
- final String richFaces = "id=person:birthdateField:birthdateDayCell24";
- final String iceFaces = "xpath=id('person:birthdateField')//table/tbody/tr[4]/td[4]/a";
- final String icefacesCalendarButton = "id=person:birthdateField:birthdate_cb";
- if (browser.isElementPresent(richFaces))
+ final String richFacesButton = "id=person:birthdateField:birthdatePopupButton";
+ final String richFacesCalendar = "xpath=//div[@class='rich-calendar-tool-btn' and text()='Today']";
+ final String iceFacesButton = "id=person:birthdateField:birthdate_cb";
+ final String iceFacesCalendar = "id=person:birthdateField:birthdate_ct";
+
+ if (browser.isElementPresent(richFacesButton))
{
- browser.click(richFaces);
+ browser.click(richFacesButton);
+ browser.waitForElement(richFacesCalendar);
+ SeleniumDateSelector.RICHFACES.setDate(browser, date);
}
- else if (browser.isElementPresent(icefacesCalendarButton))
+ else if (browser.isElementPresent(iceFacesButton))
{
- browser.click(icefacesCalendarButton);
- new Wait()
- {
-
- @Override
- public boolean until()
- {
- return browser.isElementPresent(iceFaces);
- }
- }.wait("Calendar did not appear.", Long.valueOf(SELENIUM_TIMEOUT));
- browser.click(iceFaces);
+ browser.click(iceFacesButton);
+ browser.waitForElement(iceFacesCalendar);
+ SeleniumDateSelector.ICEFACES.setDate(browser, date);
}
else
{
Modified: branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/PersonTest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/PersonTest.java 2009-08-25 15:22:31 UTC (rev 11425)
+++ branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/PersonTest.java 2009-08-25 20:00:55 UTC (rev 11426)
@@ -21,13 +21,13 @@
*/
package org.jboss.seam.test.functional.seamgen;
-import java.util.Date;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import java.util.Calendar;
+
import org.testng.annotations.Test;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.assertEquals;
-
/**
* This test verifies CRUD functionality on the Person table.
* @author Jozef Hartinger
@@ -51,7 +51,9 @@
String username = "tester";
String address = "test address";
String name = "John Doe";
- createNewPerson(username, address, new Date(), name);
+ Calendar cal = Calendar.getInstance();
+ cal.set(1991, 10, 20);
+ createNewPerson(username, address, cal.getTime(), name);
assertTrue(browser.isElementPresent(MESSAGES), "Confirmation message expected.");
assertEquals(browser.getText(MESSAGES), "Successfully created", "Unexpected confirmation message");
@@ -77,7 +79,9 @@
String editButton = String.format(PERSON_LIST_EDIT_BUTTON_BY_NAME, username);
browser.clickAndWait(editButton);
// update the entity
- fillPersonEditPage(username, address, new Date(), name);
+ Calendar cal = Calendar.getInstance();
+ cal.set(1984, 02, 29);
+ fillPersonEditPage(username, address, cal.getTime(), name);
browser.clickAndWait(PERSON_UPDATE);
// verify
assertTrue(browser.isElementPresent(MESSAGES), "Confirmation message expected.");
Modified: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeamSelenium.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeamSelenium.java 2009-08-25 15:22:31 UTC (rev 11425)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeamSelenium.java 2009-08-25 20:00:55 UTC (rev 11426)
@@ -113,6 +113,35 @@
}
/**
+ * Waits until element is asynchronously loaded on page. Uses global Selenium
+ * timeout
+ *
+ * @param locator Locator of element
+ */
+ public void waitForElement(final String locator)
+ {
+ waitForElement(locator, Long.valueOf(timeout));
+ }
+
+ /**
+ * Waits until element is asynchronously loaded on page.
+ *
+ * @param timeout Timeout in milliseconds
+ * @param locator Locator of element
+ */
+ public void waitForElement(final String locator, long timeout)
+ {
+ new Wait()
+ {
+ @Override
+ public boolean until()
+ {
+ return isElementPresent(locator);
+ }
+ }.wait("Timeout while waiting for asynchronous update of " + locator, timeout);
+ }
+
+ /**
* Returns true if icefaces detection is turned on
*/
public boolean isIcefacesDetection()
Added: branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeleniumDateSelector.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeleniumDateSelector.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/src/main/org/jboss/seam/example/common/test/selenium/SeleniumDateSelector.java 2009-08-25 20:00:55 UTC (rev 11426)
@@ -0,0 +1,261 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.example.common.test.selenium;
+
+import java.text.DateFormatSymbols;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+/**
+ * Selects date using Selenium in calendar provided by framework. Each framework
+ * is responsible for managing movement in calendar grid
+ *
+ * @author kpiwko
+ *
+ */
+public enum SeleniumDateSelector
+{
+ RICHFACES
+ {
+ @Override
+ public void setDay(SeamSelenium browser, int day)
+ {
+ String locator = "xpath=//td[contains(@class, 'rich-calendar-cell') and not(contains(@class,'rich-calendar-boundary-dates')) and text() ='" + Integer.toString(day) + "']";
+ browser.waitForElement(locator);
+ browser.click(locator);
+ }
+
+ @Override
+ public void setMonth(SeamSelenium browser, int month)
+ {
+ String monthLocator = "xpath=//div[@class='rich-calendar-tool-btn' and contains(.,',')]";
+ StringTokenizer stk = new StringTokenizer(browser.getText(monthLocator), ",");
+ String calMonth = stk.nextToken().trim();
+ int steps = monthStepsCount(calMonth, month);
+
+ movement(browser, "xpath=//div[@class='rich-calendar-tool-btn' and text()='<']", "xpath=//div[@class='rich-calendar-tool-btn' and text()='>']", steps);
+ }
+
+ @Override
+ public void setYear(SeamSelenium browser, int year)
+ {
+ String yearLocator = "xpath=//div[@class='rich-calendar-tool-btn' and contains(.,',')]";
+ StringTokenizer stk = new StringTokenizer(browser.getText(yearLocator), ",");
+ // omit first token
+ stk.nextToken();
+ String calYear = stk.nextToken().trim();
+ int steps = yearStepsCount(calYear, year);
+
+ movement(browser, "xpath=//div[@class='rich-calendar-tool-btn' and text()='<<']", "xpath=//div[@class='rich-calendar-tool-btn' and text()='>>'", steps);
+ }
+
+ },
+ ICEFACES
+ {
+ @Override
+ public void setDay(SeamSelenium browser, int day)
+ {
+ String locator = "xpath=//td[@class='iceSelInpDateDay']/a[./span/text()='" + Integer.toString(day) + "']";
+ browser.waitForElement(locator);
+ browser.click(locator);
+ }
+
+ @Override
+ public void setMonth(SeamSelenium browser, int month)
+ {
+ String monthLocator = "xpath=//td[@class='iceSelInpDateMonthYear'][2]";
+ String calMonth = browser.getText(monthLocator).trim();
+ int steps = monthStepsCount(calMonth, month);
+
+ movement(browser, "xpath=//td[@class='iceSelInpDateMonthYear'][1]/a", "xpath=//td[@class='iceSelInpDateMonthYear'][3]/a", steps);
+ }
+
+ @Override
+ public void setYear(SeamSelenium browser, int year)
+ {
+ String yearLocator = "xpath=//td[@class='iceSelInpDateMonthYear'][6]";
+ String calYear = browser.getText(yearLocator).trim();
+ int steps = yearStepsCount(calYear, year);
+
+ movement(browser, "xpath=//td[@class='iceSelInpDateMonthYear'][5]/a", "xpath=//td[@class='iceSelInpDateMonthYear'][7]/a", steps);
+ }
+
+ /**
+ * IceFaces forces partial submit, so we must wait for page reload
+ */
+ @Override
+ protected void click(SeamSelenium browser, String locator)
+ {
+ browser.clickAndWait(locator);
+ }
+
+ };
+
+ /**
+ * Selects date using Selenium browser
+ *
+ * @param browser
+ * Selenium browser instance
+ * @param date
+ * Date to be selected
+ */
+ public void setDate(SeamSelenium browser, Date date)
+ {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+
+ setYear(browser, cal.get(Calendar.YEAR));
+ setMonth(browser, cal.get(Calendar.MONTH));
+ setDay(browser, cal.get(Calendar.DAY_OF_MONTH));
+ }
+
+ /**
+ * Selects day in calendar
+ *
+ * @param browser
+ * Selenium browser instance
+ * @param day
+ * Integer containing the day to be selected, indexing from 1
+ */
+ protected abstract void setDay(SeamSelenium browser, int day);
+
+ /**
+ * Selects month in calendar
+ *
+ * @param browser
+ * Selenium browser instance
+ * @param month
+ * Integer containing the month to be selected, indexing from 1
+ */
+ protected abstract void setMonth(SeamSelenium browser, int month);
+
+ /**
+ * Selects year in calendar
+ *
+ * @param browser
+ * Selenium browser instance
+ * @param year
+ * Integer containing the year to be selected
+ */
+ protected abstract void setYear(SeamSelenium browser, int year);
+
+ /**
+ * Determines direction of month in calendar interface
+ *
+ * @param calMonth
+ * Which month is currently shown on calendar
+ * @param month
+ * Which month is desired to be set, indexing from 1
+ * @return Number of steps which must be done in either of direction, where
+ * sign has meaning:
+ * <ul>
+ * <li>- goes to past</li>
+ * <li>+ goes to future</li>
+ * </ul>
+ */
+ protected int monthStepsCount(String calMonth, int month)
+ {
+ final List<String> months = Arrays.asList(DateFormatSymbols.getInstance().getMonths());
+ int mindex = months.indexOf(calMonth);
+ if (mindex == -1)
+ throw new IllegalArgumentException("Unknown month: " + calMonth + " for locale: " + Locale.getDefault());
+
+ return month - (mindex + 1);
+ }
+
+ /**
+ * Determines direction of year in calendar interface
+ *
+ * @param calYear
+ * Which year is currently shown on calendar
+ * @param year
+ * Which month is desired to be set, indexing from 1
+ * @return Number of steps which must be done in either of direction, where
+ * sign has meaning:
+ * <ul>
+ * <li>- goes to past</li>
+ * <li>+ goes to future</li>
+ * </ul>
+ */
+ protected final int yearStepsCount(String calYear, int year)
+ {
+ int yindex;
+ try
+ {
+ yindex = Integer.valueOf(calYear);
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new IllegalArgumentException("Invalid year: " + calYear, nfe);
+ }
+
+ return year - yindex;
+ }
+
+ /**
+ * Moves in either backward or forward direction according to step count.
+ * Uses locator of element for both directions.
+ *
+ * @param browser
+ * Selenium browser instance
+ * @param backLocator
+ * Element which moves calendar to past
+ * @param forwardLocator
+ * Element which moves calendar to future
+ * @param steps
+ * Number of steps to be done, determined by monthStepsCount() or
+ * yearStepsCount() function
+ * @see SeleniumDateSelector#monthStepsCount(String, int)
+ * @see SeleniumDateSelector#yearStepsCount(String, int)
+ */
+ protected void movement(SeamSelenium browser, String backLocator, String forwardLocator, int steps)
+ {
+ // going to past
+ if (steps < 0)
+ {
+ for (int i = 0; i > steps; i--)
+ click(browser, backLocator);
+ }
+ // going to future
+ else
+ {
+ for (int i = 0; i < steps; i++)
+ click(browser, forwardLocator);
+ }
+ }
+
+ /**
+ * Clicks on element. Allow differentiate action according to framework, such
+ * as wait for page to load for IceFaces
+ *
+ * @param browser Selenium browser
+ * @param locator Locator of element to be clicked on
+ */
+ protected void click(SeamSelenium browser, String locator)
+ {
+ browser.click(locator);
+ }
+}
15 years, 4 months
Seam SVN: r11425 - branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US.
by seam-commits@lists.jboss.org
Author: denis.forveille
Date: 2009-08-25 11:22:31 -0400 (Tue, 25 Aug 2009)
New Revision: 11425
Modified:
branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Websphere.xml
Log:
Typos + text quality
JBSEAM-4324
Modified: branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Websphere.xml
===================================================================
--- branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Websphere.xml 2009-08-25 14:57:46 UTC (rev 11424)
+++ branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Websphere.xml 2009-08-25 15:22:31 UTC (rev 11425)
@@ -34,13 +34,13 @@
<para>
The following sections in this chapter assume that WebSphere is correctly installed and is
- functional, and a profile has been successfully created.
+ functional, and a WebSphere "profile" has been successfully created.
</para>
<para>
- This chapter explain how to compile, deploy and run some sample applications in WebSphere. These sample applications require
+ This chapter explains how to compile, deploy and run some sample applications in WebSphere. These sample applications require
a database. WebSphere comes by default with a set of sample applications called "Default Application". This set of sample applications
- use a Derby database running on the Derby instance installed with WebSphere. In order to keep this simple we'll use this Derby database created
+ use a Derby database running on the Derby instance installed within WebSphere. In order to keep this simple we'll use this Derby database created
for the "Default Applications". However, to run the sample application with the Derby database "as-is", a patched Hibernate
dialect must be used (The patch changes the default "auto" key generation strategy) as explained in <xref linkend="glassfish" />.
If you want to use another database, it's just a matter of creating a connection pool in WebSphere pointing to this database,
@@ -68,10 +68,10 @@
Click on the server name (<literal>server1</literal>)
</listitem>
<listitem>
- On the right navigation menu, select <literal>Web Container Settings/Web container</literal>)
+ On the right navigation menu, select <literal>Web Container Settings/Web container</literal>
</listitem>
<listitem>
- On the right navigation menu, select <literal>custom properties</literal>) and add the following properties:
+ On the right navigation menu, select <literal>custom properties</literal> and add the following properties:
<itemizedlist>
<listitem>
<literal>prependSlashToResource = true</literal>
@@ -82,7 +82,7 @@
</itemizedlist>
</listitem>
<listitem>
- Save and restart the server
+ Save the configuration and restart the server
</listitem>
</itemizedlist>
</para>
@@ -93,9 +93,7 @@
<para>
In order to use component injection, Seam needs to know how to lookup for session beans bound to the JNDI name space.
Seam provides two mechanisms to configure the way it will search for such resources:
- <itemizedlist>
- <listitem>
- The global <literal>jndi-pattern</literal> switch on the <literal><core:init></literal>. in <literal>components.xml</literal>.
+ <itemizedlist><listitem>The global <literal>jndi-pattern</literal> switch on the <literal><core:init></literal>tag in <literal>components.xml</literal>.
The switch can use a special placeholder "<literal>#{ejbName}</literal>" that resolves to the unqualified name of the EJB
</listitem>
<listitem>
@@ -110,7 +108,7 @@
</para>
<para>
- By default, WebSphere will bind the session bean in
+ By default, WebSphere will bind session beans in
its local JNDI name space under a "short" binding name that adheres to the following pattern
<literal>ejblocal:<package.qualified.local.interface.name></literal>.
</para>
@@ -120,15 +118,13 @@
<para>
As explained before, Seam needs to lookup for session bean as they appear in JNDI.
Basically, there are three strategies, in order of complexity:
- <itemizedlist>
- <listitem>
- Specify which JNDI name Seam must use for each session bean using the <literal>@JndiName</literal> annotation in the java source file
+ <itemizedlist><listitem>Specify which JNDI name Seam must use for each session bean using the <literal>@JndiName</literal> annotation in the java source file,
</listitem>
<listitem>
- Override the default session bean names generated by WebSphere to conform to the <literal>jndi-pattern</literal> attribute
+ Override the default session bean names generated by WebSphere to conform to the <literal>jndi-pattern</literal> attribute,
</listitem>
<listitem>
- Use EJB references
+ Use EJB references.
</listitem>
</itemizedlist>
</para>
@@ -182,7 +178,7 @@
That's all folks! No need to update any file during the development, nor to define any EJB to EJB or web to EJB reference!
</para>
<para>
- Compared to the other strategies, this strategy has the advantage not to have to manage any EJBs reference and also not to have to maintain extra files.
+ Compared to the other strategies, this strategy has the advantage to not have to manage any EJBs reference and also to not have to maintain extra files.
The only drawback is one extra line in the java source code with the <literal>@JndiName</literal> annotation
</para>
</section>
@@ -272,9 +268,9 @@
<title>Configuring timeouts for Stateful Session Beans</title>
<para>
A timeout value has to be set for each stateful session bean used in the application because stateful bean must not expire in WebSphere while Seam
- might still need thenm.
+ might still need them.
At the time of writing this document, WebSphere does not provide a way to configure a global timeout at neither the cluster,
- server, application nor ejb-jar level. It has to be done for each stateful bean individually.
+ server, application nor ejb-jar level. It has to be done for each stateful bean individually. By default, the default timeout is 10 minutes.
This is done by adding a file named <literal>META-INF/ibm-ejb-jar-ext.xml</literal> in the EJB module, and declare the timeout value for each bean:
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar-ext
@@ -292,7 +288,7 @@
<para>
The <literal>time-out</literal> is expressed in seconds and must be higher than the Seam conversation expiration timeout
and a few minutes higher than the user's HTTP session timeout (The session expiration timeout can trigger a few minutes
- after the number of minutes declared to expire s for the HTTP session expiration).
+ after the number of minutes declared to expire the HTTP session).
</para>
</section>
@@ -307,9 +303,14 @@
</para>
<para>
- For running this example, we'll use the second JNDI mapping strategy ("Override the default names generated by WebSphere")
- as we don't want to change the java code to add the <literal>@JndiName</literal> annotation as in the first strategy.
+ The example already has a breakout of configurations and build scripts for WebSphere. First thing, we are going to do
+ is build and deploy this example. Then we'll go over some key changes that we needed.
</para>
+
+ <para>
+ The tailored configuration files for WebSphere use the second JNDI mapping strategy ("Override the default names generated by WebSphere")
+ as the goal was to not change any java code to add the <literal>@JndiName</literal> annotation as in the first strategy.
+ </para>
<section>
<title>Building the <literal>jee5/booking</literal> example</title>
@@ -323,7 +324,7 @@
<section id="jee5-websphere-deploy">
<title>Deploying the <literal>jee5/booking</literal> example</title>
<para>
- The steps below are for the WAS version stated above.The ports are default values, if you changed them, you must substitute the values.
+ The steps below are for the WAS version stated above.The ports are the default values, if you changed them, you must substitute the values.
<orderedlist>
<listitem>
Log in to the administration console
@@ -441,7 +442,7 @@
</listitem>
<listitem>
<para>
- To start the application select our application in the list, then click on the <literal>Start</literal>
+ To start the application, select the application in the list, then click on the <literal>Start</literal>
button at the top of the table.
</para>
</listitem>
@@ -472,13 +473,13 @@
<para>
<literal>META-INF/ibm-ejb-jar-bnd.xml</literal>
— This WebSphere specific file has been added as we use the second JNDI mapping strategy.
- It defines, for each session bean, the name WebSphere will use to bind it its JNDI name space
+ It defines, for each session bean, the name WebSphere will use to bind it in its JNDI name space
</para>
</listitem>
<listitem>
<para>
<literal>META-INF/ibm-ejb-jar-ext.xml</literal>
- — This WebSphere specific file defines to WebSphere, the timeout value for each stateful bean
+ — This WebSphere specific file defines the timeout value for each stateful bean
</para>
</listitem>
<listitem>
@@ -488,7 +489,7 @@
switching to the WebSphere transaction manager lookup class,
turning off the <literal>hibernate.transaction.flush_before_completion</literal> toggle,
and forcing the Hibernate dialect to be <literal>GlassfishDerbyDialect</literal>
- how as using the integrated Derby database
+ as we are using the integrated Derby database
</para>
</listitem>
<listitem>
@@ -566,7 +567,7 @@
Follow the same instructions as for the <literal>jee5/booking</literal> sample. Select the
<literal>examples/jpa/dist-websphere7/jboss-seam-jpa.war</literal> file on the first page and on the
<literal>Map context roots for Web modules</literal> page (after the <literal>Map virtual host for Web module</literal>),
- enter the context root you want to use for your application in the <literal>Contect Root</literal> input field.
+ enter the context root you want to use for your application in the <literal>Context Root</literal> input field.
</para>
<para>
@@ -592,7 +593,7 @@
<listitem>
<para>
<literal>import.sql</literal>
- — due to the cutomized hibernate Derby dialect, the <literal>ID</literal>
+ — due to the customized hibernate Derby dialect, the <literal>ID</literal>
column can not be populated by this file and was removed.
</para>
</listitem>
15 years, 4 months
Seam SVN: r11424 - branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen.
by seam-commits@lists.jboss.org
Author: kpiwko(a)redhat.com
Date: 2009-08-25 10:57:46 -0400 (Tue, 25 Aug 2009)
New Revision: 11424
Modified:
branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/SeamGenTest.java
Log:
JBQA-2557
Modified: branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/SeamGenTest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/SeamGenTest.java 2009-08-25 12:29:17 UTC (rev 11423)
+++ branches/community/Seam_2_2/src/test/ftest/seamgen/src/main/org/jboss/seam/test/functional/seamgen/SeamGenTest.java 2009-08-25 14:57:46 UTC (rev 11424)
@@ -25,20 +25,16 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.NoSuchElementException;
import java.util.Properties;
+import java.util.StringTokenizer;
-import org.codehaus.cargo.container.ContainerType;
import org.codehaus.cargo.container.InstalledLocalContainer;
import org.codehaus.cargo.container.LocalContainer;
-import org.codehaus.cargo.container.configuration.ConfigurationType;
import org.codehaus.cargo.container.configuration.LocalConfiguration;
import org.codehaus.cargo.container.jboss.JBoss42xInstalledLocalContainer;
import org.codehaus.cargo.container.jboss.JBoss5xInstalledLocalContainer;
import org.codehaus.cargo.container.jboss.JBossExistingLocalConfiguration;
-import org.codehaus.cargo.container.jboss.JBossStandaloneLocalConfiguration;
-import org.codehaus.cargo.generic.DefaultContainerFactory;
-import org.codehaus.cargo.generic.configuration.ConfigurationFactory;
-import org.codehaus.cargo.generic.configuration.DefaultConfigurationFactory;
import org.jboss.seam.test.functional.seamgen.utils.SeamGenAdapter;
import org.openqa.selenium.server.RemoteControlConfiguration;
import org.openqa.selenium.server.SeleniumServer;
@@ -56,31 +52,31 @@
*/
public class SeamGenTest
{
-
+
protected static SeamGenAdapter seamGen;
protected static Properties seamGenProperties;
protected static Properties ftestProperties = new Properties();
-
+
protected static String SEAM_DIR;
protected static String SEAM_FTEST_PROPERTIES_FILE;
protected static String SEAMGEN_BUILDFILE;
protected static String SEAMGEN_PROPERTIES_FILE;
protected static String WORKSPACE;
-
+
// container specific properties
protected static String CONTAINER;
protected static String CONTAINER_LOCATION;
protected static int DEPLOY_TIMEOUT;
-
+
protected static boolean ICEFACES;
protected static boolean WAR;
-
+
protected static boolean DELETE_PROJECT;
protected static boolean CONTROL_CONTAINER;
-
+
protected static String TEST_SEAMGEN_PROPERTIES_FILE;
-
+
// Selenium related constants
protected static String SELENIUM_HOST;
protected static String SELENIUM_BROWSER;
@@ -89,25 +85,26 @@
protected static String SELENIUM_SPEED;
protected static String SELENIUM_TIMEOUT;
protected static long SELENIUM_ICEFACES_WAIT_TIME;
-
+ protected static String SELENIUM_SERVER_ARGS;
+
protected static String OUTPUT_DIR;
-
+
// Test application specific constants
protected static String APP_NAME;
protected static String HOME_PAGE;
-
+
// Selenium server instance
protected static SeleniumServer seleniumServer;
// Container instance
protected static LocalContainer container;
-
+
@BeforeSuite
@Parameters("seam.dir")
public void beforeSuite(@Optional(".") String seamDir) throws Exception
{
// Seam location
SEAM_DIR = seamDir;
-
+
// ftest configuration file
String relativeLocation = System.getProperty("ftest.config.location");
if (relativeLocation.equals("${ftest.config.location}"))
@@ -121,15 +118,16 @@
SEAMGEN_BUILDFILE = SEAM_DIR + "/seam-gen/build.xml";
SEAMGEN_PROPERTIES_FILE = SEAM_DIR + "/seam-gen/build.properties";
OUTPUT_DIR = SEAM_DIR + "/test-output/functional-framework/";
-
+
loadFtestProperties();
createOutputDir();
startSeleniumServer();
- if (CONTROL_CONTAINER) {
+ if (CONTROL_CONTAINER)
+ {
container = startContainer(CONTAINER, CONTAINER_LOCATION);
}
}
-
+
@AfterSuite
public void afterSuite()
{
@@ -139,7 +137,7 @@
stopContainer(container);
}
}
-
+
@BeforeTest
@Parameters( { "icefaces", "type", "suffix", "explode" })
public void setUp(@Optional("false") boolean icefaces, @Optional("ear") String type, @Optional("") String suffix, @Optional("true") boolean explode) throws Exception
@@ -148,14 +146,14 @@
WAR = type.equalsIgnoreCase("war");
APP_NAME = "seamGenTestApp" + (ICEFACES ? "Ice" : "Rich") + (WAR ? "War" : "Ear") + (explode ? "E" : "D") + suffix;
HOME_PAGE = "/" + APP_NAME + "/home.seam";
-
+
setSeamGenProperties();
-
+
seamGen = new SeamGenAdapter(SEAMGEN_BUILDFILE);
seamGen.setExplode(explode);
-
+
}
-
+
@AfterTest
public void tearDown()
{
@@ -168,21 +166,21 @@
seamGen.undeploy();
}
}
-
+
private void loadFtestProperties() throws FileNotFoundException, IOException
{
// load general properties
ftestProperties.load(new FileInputStream(SEAM_FTEST_PROPERTIES_FILE));
-
+
WORKSPACE = ftestProperties.getProperty("workspace.home");
-
+
// container specific
CONTAINER = ftestProperties.getProperty("container", "jboss5");
CONTAINER_LOCATION = ftestProperties.getProperty(CONTAINER + ".home");
DEPLOY_TIMEOUT = Integer.parseInt(ftestProperties.getProperty(CONTAINER + ".deploy.waittime")) * 1000; // miliseconds
DELETE_PROJECT = Boolean.valueOf(ftestProperties.getProperty("seamgen.delete.project", "false"));
CONTROL_CONTAINER = Boolean.valueOf(ftestProperties.getProperty("seamgen.control.container", "false"));
-
+
// load selenium constants
SELENIUM_HOST = ftestProperties.getProperty("selenium.host");
SELENIUM_BROWSER = ftestProperties.getProperty("selenium.browser");
@@ -191,14 +189,15 @@
SELENIUM_SPEED = ftestProperties.getProperty("selenium.speed");
SELENIUM_TIMEOUT = ftestProperties.getProperty("selenium.timeout");
SELENIUM_ICEFACES_WAIT_TIME = Long.valueOf(ftestProperties.getProperty("selenium.icefaces.wait.time", "2000"));
+ SELENIUM_SERVER_ARGS = ftestProperties.getProperty("selenium.server.cmd.args");
}
-
+
private void setSeamGenProperties()
{
seamGenProperties = new Properties();
-
+
String[] propertiesToCopy = { "database.type", "database.exists", "database.drop", "driver.jar", "driver.license.jar", "hibernate.connection.username", "hibernate.connection.password", "hibernate.connection.driver_class", "hibernate.connection.dataSource_class", "hibernate.cache.provider_class", "hibernate.default_catalog.null", "hibernate.default_schema.null", "hibernate.dialect", "hibernate.connection.url", "model.package", "action.package", "test.package", "richfaces.skin", "icefaces.home", "jboss.domain" };
-
+
for (String property : propertiesToCopy)
{
if (ftestProperties.get(property) != null)
@@ -206,7 +205,7 @@
seamGenProperties.put(property, ftestProperties.get(property));
}
}
-
+
// override with ftest.properties
seamGenProperties.put("workspace.home", WORKSPACE);
seamGenProperties.put("jboss.home", CONTAINER_LOCATION);
@@ -214,16 +213,85 @@
seamGenProperties.put("project.type", WAR ? "war" : "ear");
seamGenProperties.put("project.name", APP_NAME);
}
-
+
+ /**
+ * Parses some of Selenium command line arguments stated in ftest.properties.
+ * There is not orthogonality between arguments of command line and
+ * Java configuration interface, so some arguments cannot be set by this method
+ * @param rcc RC configuration to be modified
+ */
+ private void setSeleniumServerProperties(RemoteControlConfiguration rcc)
+ {
+ StringTokenizer parameters = new StringTokenizer(SELENIUM_SERVER_ARGS, " ");
+ try
+ {
+ while (parameters.hasMoreTokens())
+ {
+ String cmd = parameters.nextToken();
+ if ("-firefoxProfileTemplate".equals(cmd))
+ {
+ rcc.setFirefoxProfileTemplate(new File(parameters.nextToken()));
+ }
+ else if("-log".equals(cmd)) {
+ rcc.setLogOutFileName(parameters.nextToken());
+ }
+ else if("-singleWindow".equals(cmd)) {
+ rcc.setMultiWindow(false);
+ }
+ else if("-avoidProxy".equals(cmd)) {
+ rcc.setHonorSystemProxy(false);
+ }
+ else if("-profilesLocation".equals(cmd)) {
+ rcc.setProfilesLocation(new File(parameters.nextToken()));
+ }
+ else if("-trustAllSSLCertificates".equals(cmd)){
+ rcc.setTrustAllSSLCertificates(true);
+ }
+ else if("-interactive".equals(cmd)){
+ rcc.setInteractive(true);
+ }
+ else if("-userExtensions".equals(cmd)){
+ rcc.setUserExtensions(new File(parameters.nextToken()));
+ }
+ // injection modes
+ else if("-proxyInjectionMode".equals(cmd)){
+ rcc.setProxyInjectionModeArg(true);
+ }
+ else if("-dontInjectRegex".equals(cmd) && rcc.getProxyInjectionModeArg()) {
+ rcc.setDontInjectRegex(parameters.nextToken());
+ }
+ else if("-userJsInjection".equals(cmd) && rcc.getProxyInjectionModeArg()) {
+ rcc.setUserJSInjection(true);
+ }
+ else if("-ensureCleanSession".equals(cmd)) {
+ rcc.setReuseBrowserSessions(false);
+ }
+ else {
+ System.err.println("Unknown selenium server argument: " + cmd);
+ }
+ }
+ }
+ catch (NoSuchElementException nsee)
+ {
+ System.err.println("Invalid command line arguments in selenium.server.cmd.args (" + SELENIUM_SERVER_ARGS + ")");
+ }
+ catch (NullPointerException ioe)
+ {
+ System.err.println("Unable to open empty filename in selenium.server.cmd.args (" + SELENIUM_SERVER_ARGS+")");
+ }
+
+ }
+
private void startSeleniumServer() throws Exception
{
RemoteControlConfiguration rcc = new RemoteControlConfiguration();
rcc.setPort(SELENIUM_SERVER_PORT);
rcc.setLogOutFileName(OUTPUT_DIR + "/selenium-server.log");
+ setSeleniumServerProperties(rcc);
seleniumServer = new SeleniumServer(rcc);
seleniumServer.start();
}
-
+
private void createOutputDir()
{
File dir = new File(OUTPUT_DIR);
@@ -232,18 +300,18 @@
dir.mkdir();
}
}
-
+
public LocalContainer startContainer(String containerName, String containerHome)
{
-
+
LocalConfiguration configuration = new JBossExistingLocalConfiguration(containerHome + "/server/default");
-
+
InstalledLocalContainer container;
-
+
if (containerName.equals("jboss4"))
{
container = new JBoss42xInstalledLocalContainer(configuration);
-
+
}
else if (containerName.equals("jboss5"))
{
@@ -254,11 +322,11 @@
throw new RuntimeException("Unknown container");
}
container.setHome(containerHome);
-
+
container.start();
return container;
}
-
+
public void stopContainer(LocalContainer container)
{
container.stop();
15 years, 4 months
Seam SVN: r11423 - in branches/community/Seam_2_2/src/test/ftest: examples/ui and 3 other directories.
by seam-commits@lists.jboss.org
Author: mgencur(a)redhat.com
Date: 2009-08-25 08:29:17 -0400 (Tue, 25 Aug 2009)
New Revision: 11423
Added:
branches/community/Seam_2_2/src/test/ftest/examples/ui/photo.jpg
branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/htmlunit/
branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/htmlunit/HtmlUnitUITest.java
branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/ui.properties
Modified:
branches/community/Seam_2_2/src/test/ftest/build.xml
branches/community/Seam_2_2/src/test/ftest/examples/ui/build.xml
branches/community/Seam_2_2/src/test/ftest/examples/ui/jboss5.xml
branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/SeleniumUITest.java
Log:
JBSEAM-4386 Added a functional test for UI example
Modified: branches/community/Seam_2_2/src/test/ftest/build.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/build.xml 2009-08-25 11:00:41 UTC (rev 11422)
+++ branches/community/Seam_2_2/src/test/ftest/build.xml 2009-08-25 12:29:17 UTC (rev 11423)
@@ -36,12 +36,15 @@
<property name="lib.dir" value="${ftest.dir}/lib" />
<property name="log.dir" value="${ftest.dir}/log" />
+ <!-- Build resources -->
+ <import file="${seam.dir}/build/common.build.xml" />
+
<path id="selenium.server.classpath">
<fileset dir="${lib.dir}">
<include name="selenium-server-standalone.jar" />
</fileset>
</path>
-
+
<!-- TODO : should the libs be in seam/lib and managed with mvn? -->
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpath="../../../lib/groovy-all.jar"/>
@@ -335,11 +338,39 @@
<callExample path="@{path}" target="undeploy.example" />
</sequential>
</macrodef>
-
+
+ <!-- Target for declaring needed libraries for ftest tests -->
+ <target name="importlibraries">
+ <copyInlineDependencies id="allexamples" scope="compile" todir="${lib.dir}">
+ <dependency groupId="net.sourceforge.htmlunit" artifactId="htmlunit" version="2.3"/>
+ <dependency groupId="commons-httpclient" artifactId="commons-httpclient" version="3.1"/>
+ <dependency groupId="org.w3c" artifactId="sac" version="1.3"/>
+ <dependency groupId="commons-io" artifactId="commons-io" version="1.3.1"/>
+ <dependency groupId="commons-lang" artifactId="commons-lang" version="2.3"/>
+ <dependency groupId="apache-xerces" artifactId="xercesImpl" version="2.9.0"/>
+ <dependency groupId="commons-collections" artifactId="commons-collections" version="3.1"/>
+ <dependency groupId="commons-lang" artifactId="commons-lang" version="2.3"/>
+ <dependency groupId="apache-xalan" artifactId="xalan" version="j_2.7.0"/>
+ <dependency groupId="commons-codec" artifactId="commons-codec" version="1.3"/>
+ <dependency groupId="commons-logging" artifactId="commons-logging" version="1.1.1"/>
+ <dependency groupId="net.sourceforge.cssparser" artifactId="cssparser" version="0.9.5"/>
+ <dependency groupId="net.sourceforge.htmlunit" artifactId="htmlunit-core-js" version="2.4"/>
+ <dependency groupId="net.sourceforge.nekohtml" artifactId="nekohtml" version="1.9.9"/>
+ <dependency groupId="apache-xalan" artifactId="serializer" version="j_2.7.0"/>
+ <dependency groupId="xml-apis" artifactId="xml-apis" version="1.3.03"/>
+ </copyInlineDependencies>
+ </target>
+
+
+
<macrodef name="callExample">
<attribute name="path" />
<attribute name="target" />
<sequential>
+
+ <!-- Added for downloading libraries -->
+ <antcall target="importlibraries"> </antcall>
+
<ant dir="@{path}" target="@{target}" inheritall="false">
<property name="container" value="${container}">
</property>
Modified: branches/community/Seam_2_2/src/test/ftest/examples/ui/build.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/ui/build.xml 2009-08-25 11:00:41 UTC (rev 11422)
+++ branches/community/Seam_2_2/src/test/ftest/examples/ui/build.xml 2009-08-25 12:29:17 UTC (rev 11423)
@@ -24,4 +24,8 @@
<property name="example.name" value="ui" />
<import file="../build.xml" />
+
+ <!-- Location of Seam -->
+ <!-- <dirname property="seam.dir" file="../../../../" /> -->
+
</project>
Modified: branches/community/Seam_2_2/src/test/ftest/examples/ui/jboss5.xml
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/ui/jboss5.xml 2009-08-25 11:00:41 UTC (rev 11422)
+++ branches/community/Seam_2_2/src/test/ftest/examples/ui/jboss5.xml 2009-08-25 12:29:17 UTC (rev 11423)
@@ -1,5 +1,4 @@
-
- <!--
+<!--
JBoss, Home of Professional Open Source Copyright 2008, Red Hat
Middleware LLC, and individual contributors by the @authors tag. See
the copyright.txt in the distribution for a full listing of individual
@@ -14,13 +13,14 @@
Lesser General Public License along with this software; if not, write
to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- -->
+-->
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="UI example" verbose="2" parallel="false">
<test name="ui_jboss5">
- <parameter name="PROPERTY_FILE" value="" />
+ <parameter name="PROPERTY_FILE" value="/org/jboss/seam/example/ui/test/selenium/ui.properties" />
<classes>
<class name="org.jboss.seam.example.ui.test.selenium.SeleniumUITest" />
+ <class name="org.jboss.seam.example.ui.test.htmlunit.HtmlUnitUITest" />
</classes>
</test>
</suite>
Added: branches/community/Seam_2_2/src/test/ftest/examples/ui/photo.jpg
===================================================================
(Binary files differ)
Property changes on: branches/community/Seam_2_2/src/test/ftest/examples/ui/photo.jpg
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/htmlunit/HtmlUnitUITest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/htmlunit/HtmlUnitUITest.java (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/htmlunit/HtmlUnitUITest.java 2009-08-25 12:29:17 UTC (rev 11423)
@@ -0,0 +1,122 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.seam.example.ui.test.htmlunit;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+
+import java.io.IOException;
+
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlInput;
+import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
+import com.gargoylesoftware.htmlunit.html.HtmlImage;
+import static org.testng.AssertJUnit.fail;
+import java.net.URL;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Functional test for uploadLink and graphicImage testcases of UI example
+ *
+ * @author mgencur
+ *
+ */
+public class HtmlUnitUITest
+{
+ public static final String PAGE_URL = "http://localhost:8080/seam-ui";
+ public static final String HOME_PAGE_TITLE = "UI Example:";
+ public static final String FILE_UPLOAD_FILE= "//input[@type='file']";
+ public static final String FILE_UPLOAD_UPDATE="//input[@type='submit'][@value='Update']";
+ public static final String IMAGE_TO_UPLOAD = "photo.jpg";
+ public static final String FILE_UPLOAD_RESPONSE="//ul/li[contains(text(),'Successfully updated')]";
+ public static final String FILE_UPLOAD_LINK = "//a[contains(@href,'fileUpload')]";
+ public static final String GRAPHIC_IMAGE_LINK = "//a[contains(@href,'graphicImage')]";
+ public static final String IMAGE = "//img";
+
+ public WebClient wc;
+ public HtmlPage page;
+
+ @BeforeMethod
+ public void setUp() throws Exception{
+ URL url = new URL(PAGE_URL);
+ wc = new WebClient(BrowserVersion.FIREFOX_2);
+ page = (HtmlPage) wc.getPage(url);
+ }
+
+
+ @AfterMethod
+ public void tearDown() {
+ wc.closeAllWindows();
+ }
+
+
+ @Test
+ public void homePageLoadTest()
+ {
+ assertEquals("Unexpected page title.", HOME_PAGE_TITLE, page.getTitleText());
+ }
+
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void fileUploadTest() throws IOException {
+ final HtmlAnchor linkEl = (HtmlAnchor) page.getFirstByXPath(FILE_UPLOAD_LINK);
+
+ final HtmlPage uploadPage = (HtmlPage) linkEl.click();
+ if (uploadPage == null){
+ fail("Could not read page");
+ }
+
+ final HtmlInput el1 = (HtmlInput) uploadPage.getFirstByXPath(FILE_UPLOAD_FILE);
+ if (el1 == null) {
+ fail("Element file upload file doesn't exist");
+ } else {
+ el1.type(IMAGE_TO_UPLOAD);
+ }
+
+ final HtmlInput el2 = (HtmlInput) uploadPage.getFirstByXPath(FILE_UPLOAD_UPDATE);
+ final HtmlPage finishPage = (HtmlPage) el2.click();
+ final HtmlElement el3 = (HtmlElement) finishPage.getFirstByXPath(FILE_UPLOAD_RESPONSE);
+
+ assertFalse("Page should contain \"Successfully updated\"", el3 == null);
+ }
+
+
+ @Test(dependsOnMethods={"homePageLoadTest","fileUploadTest"})
+ public void graphicImageTest() throws IOException {
+ final HtmlAnchor linkEl = (HtmlAnchor) page.getFirstByXPath(GRAPHIC_IMAGE_LINK);
+
+ final HtmlPage graphicPage = (HtmlPage) linkEl.click();
+ if (graphicPage == null){
+ fail("Could not read page");
+ }
+
+ final HtmlImage image = (HtmlImage) graphicPage.getFirstByXPath(IMAGE);
+
+ assertFalse("Page should contain image of Pete Muir", image == null);
+ }
+}
Modified: branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/SeleniumUITest.java
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/SeleniumUITest.java 2009-08-25 11:00:41 UTC (rev 11422)
+++ branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/SeleniumUITest.java 2009-08-25 12:29:17 UTC (rev 11423)
@@ -1,16 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jboss.seam.example.ui.test.selenium;
import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
import org.jboss.seam.example.common.test.selenium.SeamSeleniumTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+/**
+ * This class tests functionality of UI example
+ *
+ * @author Martin Gencur
+ *
+ */
public class SeleniumUITest extends SeamSeleniumTest
{
public static final String HOME_PAGE = "/index.seam";
public static final String HOME_PAGE_TITLE = "UI Example:";
-
+ public static final String SELECT_ITEMS_LINK = "xpath=//a[contains(@href,\"selectItems\")]";
+ public static final String FRAGMENT_LINK = "xpath=//a[contains(@href,\"fragment\")]";
+ public static final String FOTMATTED_TEXT_LINK = "xpath=//a[contains(@href,\"formattedText\")]";
+ public static final String BUTTON_AND_SLINK_LINK = "xpath=//a[contains(@href,\"linkAndButton\")]";
+ public static final String CACHE_LINK = "xpath=//a[contains(@href,\"cache\")]";
+ public static final String VALIDATE_EQUALITY_LINK = "xpath=//a[contains(@href,\"equalityValidator\")]";
+ public static final String VALIDATE_EQUALITY2_LINK = "xpath=//a[contains(@href,\"equalityValidatorWConvert\")]";
+
@BeforeMethod
@Override
public void setUp()
@@ -26,5 +61,137 @@
public void homePageLoadTest()
{
assertEquals("Unexpected page title.", HOME_PAGE_TITLE, browser.getTitle());
+ }
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void selectItemsTest(){
+ String title = "Mr.";
+ String name = "Martin Gencur";
+ String continent = "Europe";
+ String age = "24";
+ String pet = "Dog (Needs lots of exercise)";
+ String colour1 = "Green", colour2 = "Yellow";
+ String book = "Pride and Prejudice by Jane Austin (British)";
+ String film = "Blade Runner directed by Ridley Scott";
+ browser.clickAndWait(SELECT_ITEMS_LINK);
+ browser.select(getProperty("SELECT_ITEMS_TITLE"), "label="+title);
+ browser.type(getProperty("SELECT_ITEMS_NAME"), name);
+ browser.select(getProperty("SELECT_ITEMS_CONTINENT"), "label="+continent);
+ browser.check(getProperty("SELECT_ITEMS_USER"));
+ browser.check(getProperty("SELECT_ITEMS_ADMIN"));
+ browser.check(getProperty("SELECT_ITEMS_MANAGER"));
+ browser.check(getProperty("SELECT_ITEMS_SUPERADMIN"));
+ browser.select(getProperty("SELECT_ITEMS_AGE"), "label="+age);
+ browser.select(getProperty("SELECT_ITEMS_PET"), "label="+pet);
+ browser.select(getProperty("SELECT_ITEMS_COLOURS"), "label="+colour1);
+ browser.select(getProperty("SELECT_ITEMS_COLOURS"), "label="+colour2);
+ browser.select(getProperty("SELECT_ITEMS_BOOK"), "label="+book);
+ browser.select(getProperty("SELECT_ITEMS_FILM"), "label="+film);
+ browser.clickAndWait(getProperty("SELECT_ITEMS_APPLY"));
+ browser.check(getProperty("SELECT_ITEMS_COUNTRY"));
+ browser.clickAndWait(getProperty("SELECT_ITEMS_APPLY"));
+ assertTrue("Page should contain \"Successfully updated\"", browser.isTextPresent("Successfully updated"));
}
+
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void fragmentTest(){
+ browser.clickAndWait(FRAGMENT_LINK);
+ assertTrue("Page should contain \"fragment is rendered\"", browser.isTextPresent("This fragment is rendered whilst"));
+ }
+
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void formattedTextTest(){
+ browser.clickAndWait(FOTMATTED_TEXT_LINK);
+ assertTrue("Page should contain information about Pete Muir working all the time on Seam", browser.isTextPresent("works on Seam, of course"));
+ }
+
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void buttonAndLinkTest(){
+ browser.clickAndWait(BUTTON_AND_SLINK_LINK);
+ assertTrue("Page should contain \"A fragment to jump to\"", browser.isTextPresent("A fragment to jump to"));
+ browser.clickAndWait(getProperty("JUMP_LINK"));
+ browser.clickAndWait(getProperty("JUMP_BUTTON"));
+ browser.clickAndWait(getProperty("LINK_LINK"));
+ browser.clickAndWait(getProperty("DO_ACTION_LINK"));
+ assertTrue("Page should contain \"A simple action was performed\"", browser.isTextPresent("A simple action was performed"));
+ browser.clickAndWait(getProperty("DO_ACTION_BUTTON"));
+ assertTrue("Page should contain \"A simple action was performed\"", browser.isTextPresent("A simple action was performed"));
+ assertTrue("Page should contain disabled link", browser.isElementPresent(getProperty("DISABLED_DO_ACTION_LINK")));
+ assertTrue("Page should contain disabled button", browser.isElementPresent(getProperty("DISABLED_DO_ACTION_BUTTON")));
+ browser.clickAndWait(getProperty("BEGIN_CONVERSATION_LINK"));
+ browser.clickAndWait(getProperty("END_CONVERSATION_BUTTON"));
+ assertTrue("Page shouldn't contain \"A simple action was performed\"", !browser.isTextPresent("A simple action was performed"));
+ browser.clickAndWait(getProperty("ADD_PARAMETER_LINK"));
+ browser.clickAndWait(getProperty("ADD_PARAMETER_BUTTON"));
+ assertTrue("Page should contain \"Foo = bar\"", browser.isTextPresent("Foo = bar"));
+ }
+
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void cacheTest(){
+ browser.clickAndWait(CACHE_LINK);
+ assertTrue("Page should contain some cached text", browser.isTextPresent("Some cached text"));
+ }
+
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void validateEqualityTest(){
+ String name1 = "martin";
+ String name2 = "peter";
+ String age1 = "20";
+ String age2 = "30";
+ browser.clickAndWait(VALIDATE_EQUALITY_LINK);
+
+ browser.type(getProperty("NAME_INPUT"), name1);
+ browser.type(getProperty("NAME_VERIFICATION_INPUT"), name1);
+ browser.clickAndWait(getProperty("CHECK_NAME_BUTTON"));
+ assertTrue("Page should contain \"OK!\""+ "je tam:" + browser.getBodyText(), browser.isTextPresent("OK!"));
+
+ browser.type(getProperty("NAME_INPUT"), name1);
+ browser.type(getProperty("NAME_VERIFICATION_INPUT"), name2);
+ browser.clickAndWait(getProperty("CHECK_NAME_BUTTON"));
+ assertTrue("Page should contain \"Must be the same as name!\"", browser.isTextPresent("Must be the same as name!"));
+
+ browser.type(getProperty("MINIMUM_AGE_INPUT"), age1);
+ browser.type(getProperty("MAXIMUM_AGE_INPUT"), age2);
+ browser.clickAndWait(getProperty("CHECK_AGES_BUTTON"));
+ assertTrue("Page should contain \"OK!\"", browser.isTextPresent("OK!"));
+ browser.type(getProperty("MINIMUM_AGE_INPUT"), age1);
+ browser.type(getProperty("MAXIMUM_AGE_INPUT"), age1);
+ browser.clickAndWait(getProperty("CHECK_AGES_BUTTON"));
+ assertTrue("Page should contain \"Must be larger than minimum!\"", browser.isTextPresent("Must be larger than minimum!"));
+ browser.type(getProperty("MINIMUM_AGE_INPUT"), age2);
+ browser.type(getProperty("MAXIMUM_AGE_INPUT"), age1);
+ browser.clickAndWait(getProperty("CHECK_AGES_BUTTON"));
+ assertTrue("Page should contain \"Must be larger than minimum!\"", browser.isTextPresent("Must be larger than minimum!"));
+ }
+
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void validateEquality2Test(){
+ String date1 = "2009-08-21";
+ String date2 = "2009-08-25";
+ browser.clickAndWait(VALIDATE_EQUALITY2_LINK);
+
+ browser.type(getProperty("DATE_INPUT"), date1);
+ browser.type(getProperty("DATE_VERIFICATION_INPUT"), date1);
+ browser.clickAndWait(getProperty("CHECK_DATE_BUTTON"));
+ assertTrue("Page should contain \"OK!\"", browser.isTextPresent("OK!"));
+
+ browser.type(getProperty("DATE_INPUT"), date1);
+ browser.type(getProperty("DATE_VERIFICATION_INPUT"), date2);
+ browser.clickAndWait(getProperty("CHECK_DATE_BUTTON"));
+ assertTrue("Page should contain \"Value does not equal that in 'date'\"", browser.isTextPresent("Value does not equal that in 'date' "));
+ //assertTrue("Page should contain information about Pete Muir working all the time on Seam", browser.isTextPresent("works on Seam, of course"));
+ }
+
+ /**
+ * Resource download cannot be tested automatically because downloading a file needs user interaction
+ * with a window form
+ *
+ @Test(dependsOnMethods={"homePageLoadTest"})
+ public void resourceDownloadTest(){
+ }*/
}
Added: branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/ui.properties
===================================================================
--- branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/ui.properties (rev 0)
+++ branches/community/Seam_2_2/src/test/ftest/examples/ui/src/org/jboss/seam/example/ui/test/selenium/ui.properties 2009-08-25 12:29:17 UTC (rev 11423)
@@ -0,0 +1,34 @@
+SELECT_ITEMS_TITLE=xpath\=//select[option[contains(@value,'MR')]]
+SELECT_ITEMS_NAME=xpath\=//input[contains(@value,'Peter Muir')]
+SELECT_ITEMS_CONTINENT=xpath\=//select[option[contains(text(),'Europe')]]
+SELECT_ITEMS_USER=xpath\=//input[@type\='checkbox'][@value\='USER']
+SELECT_ITEMS_ADMIN=xpath\=//input[@type\='checkbox'][@value\='ADMIN']
+SELECT_ITEMS_MANAGER=xpath\=//input[@type\='checkbox'][@value\='MANAGER']
+SELECT_ITEMS_SUPERADMIN=xpath\=//input[@type\='checkbox'][@value\='SUPERADMIN']
+SELECT_ITEMS_AGE=xpath\=//select[option[contains(text(),'24')]]
+SELECT_ITEMS_PET=xpath\=//select[option[contains(@value,'Dog')]]
+SELECT_ITEMS_COLOURS=xpath\=//select[option[contains(text(),'Green')]]
+SELECT_ITEMS_BOOK=xpath\=//select[option[contains(text(),'Pride and Prejudice by Jane Austin (British)')]]
+SELECT_ITEMS_FILM=xpath\=//select[option[contains(text(),'Blade Runner directed by Ridley Scott')]]
+SELECT_ITEMS_APPLY=xpath\=//input[@type\='submit'][@value\='Apply']
+SELECT_ITEMS_COUNTRY=xpath\=//input[@type\='radio'][@value\='18']
+JUMP_LINK=xpath\=//a[contains(text(),'Jump')]
+JUMP_BUTTON=xpath\=//input[@type\='button'][@value\='Jump']
+LINK_LINK=xpath\=//a[contains(text(),'Link')]
+DO_ACTION_LINK=xpath\=//a[contains(text(),'Do action')]
+DO_ACTION_BUTTON=xpath\=//input[@type\='button'][@value\='Do action']
+DISABLED_DO_ACTION_LINK=xpath\=//a[contains(text(),'Do action')][not(@href)]
+DISABLED_DO_ACTION_BUTTON=xpath\=//input[@type\='button'][@value\='Do action'][@disabled\='disabled']
+BEGIN_CONVERSATION_LINK=xpath\=//a[contains(text(),'Begin conversation')]
+END_CONVERSATION_BUTTON=xpath\=//input[@type\='button'][@value\='End conversation']
+ADD_PARAMETER_LINK=xpath\=//a[contains(text(),'Add a page parameter')]
+ADD_PARAMETER_BUTTON=xpath\=//input[@type\='button'][@value\='Add a page parameter']
+NAME_INPUT=xpath\=//input[@type\='text'][contains(@name,'name')][not(contains(@name,'nameVerification'))]
+NAME_VERIFICATION_INPUT=xpath\=//input[@type\='text'][contains(@name,'nameVerification')]
+CHECK_NAME_BUTTON=xpath\=//input[@type\='submit'][@value\='Check name']
+MINIMUM_AGE_INPUT=xpath\=//input[@type\='text'][contains(@name,'min')][not(contains(@name,'minVerification'))]
+MAXIMUM_AGE_INPUT=xpath\=//input[@type\='text'][contains(@name,'minVerification')]
+CHECK_AGES_BUTTON=xpath\=//input[@type\='submit'][@value\='Check ages']
+DATE_INPUT=xpath\=//input[@type\='text'][contains(@name,'date')][not(contains(@name,'dateVerification'))]
+DATE_VERIFICATION_INPUT=xpath\=//input[@type\='text'][contains(@name,'dateVerification')]
+CHECK_DATE_BUTTON=xpath\=//input[@type\='submit'][@value\='Check date']
\ No newline at end of file
15 years, 4 months
Seam SVN: r11422 - branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging.
by seam-commits@lists.jboss.org
Author: manaRH
Date: 2009-08-25 07:00:41 -0400 (Tue, 25 Aug 2009)
New Revision: 11422
Added:
branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/UserTokens.java
Modified:
branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/SubscriptionRegistry.java
Log:
JBPAPP-2362
Modified: branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/SubscriptionRegistry.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/SubscriptionRegistry.java 2009-08-25 08:16:50 UTC (rev 11421)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/SubscriptionRegistry.java 2009-08-25 11:00:41 UTC (rev 11422)
@@ -153,30 +153,35 @@
}
}
- /**
- *
- * @return Set
- */
- public Set getUserTokens()
+ public UserTokens getUserTokens()
{
- Context session = Contexts.getSessionContext();
- if (session.get(CONTEXT_USER_TOKENS) == null)
- {
- synchronized(session)
- {
- if (session.get(CONTEXT_USER_TOKENS) == null)
- session.set(CONTEXT_USER_TOKENS, new HashSet<String> ());
- }
- }
- return (Set) session.get(CONTEXT_USER_TOKENS);
+ return (UserTokens) Component.getInstance(UserTokens.class);
}
public RemoteSubscriber getSubscription(String token)
{
- if (!getUserTokens().contains(token))
- throw new IllegalArgumentException(
- "Invalid token argument - token not found in Session Context.");
-
+ if (!getUserTokens().contains(token)) {
+ throw new IllegalArgumentException("Invalid token argument - token not found in Session Context.");
+ }
+
return subscriptions.get(token);
}
+
+ public Set<String> getAllTokens() {
+ return subscriptions.keySet();
+ }
+
+ public void cleanupTokens(Set<String> tokens)
+ {
+ for (String token: tokens) {
+ RemoteSubscriber subscriber = subscriptions.remove(token);
+ if (subscriber!=null) {
+ try {
+ subscriber.unsubscribe();
+ } catch (Exception e) {
+ log.debug("problem cleaning up subcription", e);
+ }
+ }
+ }
+ }
}
Added: branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/UserTokens.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/UserTokens.java (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/remoting/org/jboss/seam/remoting/messaging/UserTokens.java 2009-08-25 11:00:41 UTC (rev 11422)
@@ -0,0 +1,33 @@
+package org.jboss.seam.remoting.messaging;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Destroy;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+
+@Name("org.jboss.seam.remoting.messaging.SubscriptionRegistry.userTokens")
+(a)Scope(ScopeType.SESSION)
+public class UserTokens
+{
+ Set<String> tokens = new HashSet<String>();
+
+ public void add(String token) {
+ tokens.add(token);
+ }
+
+ public boolean contains(String token) {
+ return tokens.contains(token);
+ }
+
+ public void remove(String token) {
+ tokens.remove(token);
+ }
+
+ @Destroy
+ public void cleanUp() {
+ SubscriptionRegistry.instance().cleanupTokens(tokens);
+ }
+}
15 years, 4 months
Seam SVN: r11421 - in branches/community/Seam_2_2/examples/wiki: src/etc/META-INF and 1 other directories.
by seam-commits@lists.jboss.org
Author: christian.bauer(a)jboss.com
Date: 2009-08-25 04:16:50 -0400 (Tue, 25 Aug 2009)
New Revision: 11421
Modified:
branches/community/Seam_2_2/examples/wiki/build.xml
branches/community/Seam_2_2/examples/wiki/src/etc/META-INF/components-prod.xml
branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiPluginThemeResource.java
branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiSecurityEvents.java
branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiUserPortraitResource.java
Log:
Optimized HTTP caching etc. for wiki production profile
Modified: branches/community/Seam_2_2/examples/wiki/build.xml
===================================================================
--- branches/community/Seam_2_2/examples/wiki/build.xml 2009-08-25 08:14:23 UTC (rev 11420)
+++ branches/community/Seam_2_2/examples/wiki/build.xml 2009-08-25 08:16:50 UTC (rev 11421)
@@ -165,7 +165,8 @@
destdir="${classes.dir}"
debug="${javac.debug}"
deprecation="${javac.deprecation}"
- nowarn="${javac.nowarn}">
+ nowarn="${javac.nowarn}"
+ target="1.5">
<src path="${src.java.dir}"/>
<src path="${src.plugin.dir}"/>
</javac>
@@ -399,7 +400,8 @@
destdir="${testclasses.dir}"
debug="${javac.debug}"
deprecation="${javac.deprecation}"
- nowarn="${javac.nowarn}">
+ nowarn="${javac.nowarn}"
+ target="1.5">
<classpath>
<path refid="test.classpath" />
<path refid="runtime.emma.path" />
Modified: branches/community/Seam_2_2/examples/wiki/src/etc/META-INF/components-prod.xml
===================================================================
--- branches/community/Seam_2_2/examples/wiki/src/etc/META-INF/components-prod.xml 2009-08-25 08:14:23 UTC (rev 11420)
+++ branches/community/Seam_2_2/examples/wiki/src/etc/META-INF/components-prod.xml 2009-08-25 08:16:50 UTC (rev 11421)
@@ -38,6 +38,15 @@
-->
<web:multipart-filter create-temp-files="true" max-request-size="10000000" url-pattern="*.seam"/>
+ <web:cache-control-filter name="resourcesCacheControlFilter"
+ regex-url-pattern=".*(\.gif|\.png|\.jpg|\.jpeg|\.css|\.js)"
+ value="max-age=86400"/> <!-- 1 day -->
+
+ <web:cache-control-filter name="userPortraitCacheControlFilter"
+ url-pattern="/seam/resource/wikiUserPortrait/*"
+ value="max-age=432000"/> <!-- 5 days -->
+
+
<!-- ############## END OF WIKI USER CONFIGURATION ############## -->
<!-- Running in regular JBoss AS, Seam starts the persistence unit -->
Modified: branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiPluginThemeResource.java
===================================================================
--- branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiPluginThemeResource.java 2009-08-25 08:14:23 UTC (rev 11420)
+++ branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiPluginThemeResource.java 2009-08-25 08:16:50 UTC (rev 11421)
@@ -10,23 +10,22 @@
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.core.Expressions;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
import org.jboss.seam.util.Resources;
-import org.jboss.seam.web.AbstractResource;
+import org.jboss.seam.web.ConditionalAbstractResource;
import org.jboss.seam.wiki.core.plugin.PluginRegistry;
import org.jboss.seam.wiki.core.plugin.metamodel.Plugin;
import org.jboss.seam.wiki.core.plugin.metamodel.PluginModule;
-import org.jboss.seam.core.Expressions;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,7 +48,7 @@
@Scope(APPLICATION)
@Name("wikiPluginThemeResource")
@BypassInterceptors
-public class WikiPluginThemeResource extends AbstractResource {
+public class WikiPluginThemeResource extends ConditionalAbstractResource {
private Log log = Logging.getLog(WikiPluginThemeResource.class);
@@ -62,6 +61,18 @@
// Resources that are interpolated, i.e. which are text files that contain EL expressions
private String[] interpolatedResourcesExtensions = new String[]{"css"};
+ private Map<String, String> mimeTypesExtensions = new HashMap() {{
+ put("css", "text/css");
+ put("txt", "text/plain");
+ put("js", "text/javascript");
+ put("png", "image/png");
+ put("jpg", "image/jpg");
+ put("jpeg", "image/jpeg");
+ put("gif", "image/gif");
+ put("swf", "application/x-shockwave-flash");
+ put("flv", "video/x-flv");
+ }};
+
@Override
public String getResourcePath() {
return Plugin.REGISTER_SEAM_RESOURCE_THEME;
@@ -146,24 +157,52 @@
boolean isInterpolated = false;
for (String interpolatedResourcesExtension : interpolatedResourcesExtensions) {
- if (interpolatedResourcesExtension.equals(themeResourceExtension)) isInterpolated = true;
+ if (interpolatedResourcesExtension.equals(themeResourceExtension)) {
+ isInterpolated = true;
+ break;
+ }
}
+ String contentType = mimeTypesExtensions.get(themeResourceExtension);
+
if (isInterpolated) {
- log.debug("serving interpolated resource: " + resourcePath);
+
+ if (contentType == null) {
+ contentType = "text/plain";
+ }
+ response.setContentType(contentType);
+
CharSequence textFile = readFile(in);
textFile = parseEL(textFile);
- response.getWriter().write(textFile.toString());
- response.getWriter().flush();
+
+ String entityTag = createEntityTag(textFile.toString(), false);
+ Long lastModified = getLastModifiedTimestamp(resourcePath);
+
+ if (!sendConditional(request, response, entityTag, lastModified)) {
+ log.debug("serving interpolated resource: " + resourcePath);
+ OutputStreamWriter outStream = new OutputStreamWriter(selectOutputStream(request, response));
+ outStream.write(textFile.toString());
+ outStream.close();
+ }
} else {
log.debug("serving resource: " + resourcePath);
- byte[] buffer = new byte[1024];
- int read = in.read(buffer);
- while (read != -1) {
- response.getOutputStream().write(buffer, 0, read);
- read = in.read(buffer);
+
+ if (contentType == null) {
+ contentType = "application/octet-stream";
}
- response.getOutputStream().flush();
+ response.setContentType(contentType);
+
+ // We can't produce an entity tag because we stream the bytes through (or not, through the gzip wrapper)
+ if (!sendConditional(request, response, null, getLastModifiedTimestamp(resourcePath))) {
+ OutputStream outStream = selectOutputStream(request, response);
+ byte[] buffer = new byte[1024];
+ int read = in.read(buffer);
+ while (read != -1) {
+ outStream.write(buffer, 0, read);
+ read = in.read(buffer);
+ }
+ outStream.close();
+ }
}
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND, resourcePath);
Modified: branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiSecurityEvents.java
===================================================================
--- branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiSecurityEvents.java 2009-08-25 08:14:23 UTC (rev 11420)
+++ branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiSecurityEvents.java 2009-08-25 08:16:50 UTC (rev 11421)
@@ -16,6 +16,8 @@
import org.jboss.seam.security.Identity;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.wiki.core.action.WikiRequestResolver;
+import org.jboss.seam.wiki.core.model.User;
+import org.jboss.seam.Component;
/**
* Overrides the "login failed" message and turns it into a WARN (we don't want INFO here).
@@ -47,7 +49,7 @@
);
Contexts.getSessionContext().set(
- WikiRequestResolver.SESSION_MSG_DATA, Identity.instance().getCredentials().getUsername()
+ WikiRequestResolver.SESSION_MSG_DATA, ((User)Component.getInstance("currentUser")).getFullname()
);
}
Modified: branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiUserPortraitResource.java
===================================================================
--- branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiUserPortraitResource.java 2009-08-25 08:14:23 UTC (rev 11420)
+++ branches/community/Seam_2_2/examples/wiki/src/main/org/jboss/seam/wiki/core/ui/WikiUserPortraitResource.java 2009-08-25 08:16:50 UTC (rev 11421)
@@ -90,8 +90,6 @@
return;
}
- response.addHeader("Cache-Control", "max-age=600"); // 10 minutes freshness in browser cache
-
byte[] image = imageSize.equals("l") ? user.getProfile().getImage() : user.getProfile().getSmallImage();
response.setContentType(user.getProfile().getImageContentType());
response.setContentLength(image.length);
15 years, 4 months
Seam SVN: r11420 - in branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay: test and 1 other directory.
by seam-commits@lists.jboss.org
Author: christian.bauer(a)jboss.com
Date: 2009-08-25 04:14:23 -0400 (Tue, 25 Aug 2009)
New Revision: 11420
Added:
branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/plain/PlainRootResource.java
Modified:
branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java
Log:
More tests for Restbay example
Added: branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/plain/PlainRootResource.java
===================================================================
--- branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/plain/PlainRootResource.java (rev 0)
+++ branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/resteasy/plain/PlainRootResource.java 2009-08-25 08:14:23 UTC (rev 11420)
@@ -0,0 +1,20 @@
+package org.jboss.seam.example.restbay.resteasy.plain;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.GET;
+
+/**
+ * @author Christian Bauer
+ */
+@Path("/")
+public class PlainRootResource
+{
+
+ @GET
+ @Produces("text/plain")
+ public String getResource()
+ {
+ return "Root";
+ }
+}
Modified: branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java
===================================================================
--- branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java 2009-08-25 08:13:36 UTC (rev 11419)
+++ branches/community/Seam_2_2/examples/restbay/src/org/jboss/seam/example/restbay/test/BasicServiceTest.java 2009-08-25 08:14:23 UTC (rev 11420)
@@ -115,6 +115,21 @@
};
}
+ @Test
+ public void testRootResource() throws Exception {
+ new ResourceRequest(requestEnv, Method.GET, "/restv1/")
+ {
+
+ @Override
+ protected void onResponse(EnhancedMockHttpServletResponse response)
+ {
+ assertEquals(response.getStatus(), 200);
+ assertEquals(response.getContentAsString(), "Root");
+ }
+
+ }.run();
+ }
+
@Test(dataProvider = "queryPaths")
public void testExeptionMapping(final String resourcePath) throws Exception
{
15 years, 4 months
Seam SVN: r11419 - in branches/community/Seam_2_2: src/main/org/jboss/seam and 3 other directories.
by seam-commits@lists.jboss.org
Author: christian.bauer(a)jboss.com
Date: 2009-08-25 04:13:36 -0400 (Tue, 25 Aug 2009)
New Revision: 11419
Added:
branches/community/Seam_2_2/src/main/org/jboss/seam/web/CacheControlFilter.java
branches/community/Seam_2_2/src/main/org/jboss/seam/web/ConditionalAbstractResource.java
branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/web/ConditionalRequestTest.java
Modified:
branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Configuration.xml
branches/community/Seam_2_2/src/main/org/jboss/seam/web-2.2.xsd
branches/community/Seam_2_2/src/main/org/jboss/seam/web/AbstractResource.java
branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/testng.xml
Log:
JBSEAM-4383, infrastructure for HTTP optimization
Modified: branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Configuration.xml
===================================================================
--- branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Configuration.xml 2009-08-24 13:41:30 UTC (rev 11418)
+++ branches/community/Seam_2_2/doc/Seam_Reference_Guide/en-US/Configuration.xml 2009-08-25 08:13:36 UTC (rev 11419)
@@ -374,8 +374,36 @@
</sect3>
-
<sect3>
+ <title>Enabling HTTP cache-control headers</title>
+ <para>
+ Seam does <emphasis>not</emphasis> automatically add <literal>cache-control</literal> HTTP headers to
+ any resources served by the Seam resource servlet, or directly from your view directory by the servlet
+ container. This means that your images, Javascript and CSS files, and resource representations from
+ Seam resource servlet such as Seam Remoting Javascript interfaces are usually not cached by the browser.
+ This is convenient in development but should be changed in production when optimizing the application.
+ </para>
+
+ <para>
+ You can configure a Seam filter to enable automatic addition of <literal>cache-control</literal> headers
+ depending on the requested URI in <literal>components.xml</literal>:
+ </para>
+
+ <programlisting role="XML"><![CDATA[<web:cache-control-filter name="commonTypesCacheControlFilter"
+ regex-url-pattern=".*(\.gif|\.png|\.jpg|\.jpeg|\.css|\.js)"
+ value="max-age=86400"/> <!-- 1 day -->
+
+<web:cache-control-filter name="anotherCacheControlFilter"
+ url-pattern="/my/cachable/resources/*"
+ value="max-age=432000"/> <!-- 5 days -->]]></programlisting>
+
+ <para>
+ You do not have to name the filters unless you have more than one filter enabled.
+ </para>
+
+ </sect3>
+
+ <sect3>
<title>Adding custom filters</title>
<para> Seam can install your filters for you, allowing you to specify <emphasis>where</emphasis> in the
chain your filter is placed (the servlet specification doesn't provide a well defined order if you
Modified: branches/community/Seam_2_2/src/main/org/jboss/seam/web/AbstractResource.java
===================================================================
--- branches/community/Seam_2_2/src/main/org/jboss/seam/web/AbstractResource.java 2009-08-24 13:41:30 UTC (rev 11418)
+++ branches/community/Seam_2_2/src/main/org/jboss/seam/web/AbstractResource.java 2009-08-25 08:13:36 UTC (rev 11419)
@@ -1,42 +1,177 @@
package org.jboss.seam.web;
-import java.io.IOException;
-
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.zip.GZIPOutputStream;
/**
- * Superclass of Seam components that serve up
- * "resources" to the client via the Seam
+ * Superclass of Seam components that serve up
+ * "resources" to the client via the Seam
* resource servlet. Note that since a filter is
* potentially called outside of a set of Seam
- * contexts, it is not a true Seam component.
+ * contexts, it is not a true Seam component.
* However, we are able to reuse the functionality
- * for component scanning, installation and
+ * for component scanning, installation and
* configuration for filters. All resources
* must extend this class.
- *
+ *
* @author Shane Bryzak
*
*/
public abstract class AbstractResource
{
private ServletContext context;
-
+
protected ServletContext getServletContext()
{
return context;
}
-
+
public void setServletContext(ServletContext context)
{
this.context = context;
}
-
+
public abstract void getResource(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
-
+
public abstract String getResourcePath();
+
+ protected OutputStream selectOutputStream(HttpServletRequest request, HttpServletResponse response)
+ throws IOException
+ {
+
+ String acceptEncoding = request.getHeader("Accept-Encoding");
+ String mimeType = response.getContentType();
+
+ if (isGzipEnabled()
+ && acceptEncoding != null
+ && acceptEncoding.length() > 0
+ && acceptEncoding.indexOf("gzip") > -1
+ && isCompressedMimeType(mimeType))
+ {
+ return new GZIPResponseStream(response);
+ }
+ else
+ {
+ return response.getOutputStream();
+ }
+ }
+
+ protected boolean isCompressedMimeType(String mimeType)
+ {
+ return mimeType.matches("text/.+");
+ }
+
+ protected boolean isGzipEnabled()
+ {
+ return true;
+ }
+
+ /*
+ * Copyright 2004-2008 the original author or authors.
+ *
+ * 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.
+ *
+ * @See org/springframework/js/resource/ResourceServlet.java
+ */
+ private class GZIPResponseStream extends ServletOutputStream
+ {
+
+ private ByteArrayOutputStream byteStream = null;
+
+ private GZIPOutputStream gzipStream = null;
+
+ private boolean closed = false;
+
+ private HttpServletResponse response = null;
+
+ private ServletOutputStream servletStream = null;
+
+ public GZIPResponseStream(HttpServletResponse response) throws IOException
+ {
+ super();
+ closed = false;
+ this.response = response;
+ this.servletStream = response.getOutputStream();
+ byteStream = new ByteArrayOutputStream();
+ gzipStream = new GZIPOutputStream(byteStream);
+ }
+
+ public void close() throws IOException
+ {
+ if (closed)
+ {
+ throw new IOException("This output stream has already been closed");
+ }
+ gzipStream.finish();
+
+ byte[] bytes = byteStream.toByteArray();
+
+ response.setContentLength(bytes.length);
+ response.addHeader("Content-Encoding", "gzip");
+ servletStream.write(bytes);
+ servletStream.flush();
+ servletStream.close();
+ closed = true;
+ }
+
+ public void flush() throws IOException
+ {
+ if (closed)
+ {
+ throw new IOException("Cannot flush a closed output stream");
+ }
+ gzipStream.flush();
+ }
+
+ public void write(int b) throws IOException
+ {
+ if (closed)
+ {
+ throw new IOException("Cannot write to a closed output stream");
+ }
+ gzipStream.write((byte) b);
+ }
+
+ public void write(byte b[]) throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ public void write(byte b[], int off, int len) throws IOException
+ {
+ if (closed)
+ {
+ throw new IOException("Cannot write to a closed output stream");
+ }
+ gzipStream.write(b, off, len);
+ }
+
+ public boolean closed()
+ {
+ return (this.closed);
+ }
+
+ public void reset()
+ {
+ // noop
+ }
+ }
}
Added: branches/community/Seam_2_2/src/main/org/jboss/seam/web/CacheControlFilter.java
===================================================================
--- branches/community/Seam_2_2/src/main/org/jboss/seam/web/CacheControlFilter.java (rev 0)
+++ branches/community/Seam_2_2/src/main/org/jboss/seam/web/CacheControlFilter.java 2009-08-25 08:13:36 UTC (rev 11419)
@@ -0,0 +1,64 @@
+package org.jboss.seam.web;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.annotations.web.Filter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Provides automatic addition of cache-control HTTP headers to matching resource responses.
+ *
+ * @author Christian Bauer
+ */
+(a)Scope(ScopeType.APPLICATION)
+@Name("org.jboss.seam.web.cacheControlFilter")
+@Install(value = false, precedence = Install.BUILT_IN)
+@BypassInterceptors
+@Filter(within = "org.jboss.seam.web.exceptionFilter")
+public class CacheControlFilter extends AbstractFilter
+{
+
+ private static final LogProvider log = Logging.getLogProvider(CacheControlFilter.class);
+
+ private String value;
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException
+ {
+
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+
+ if (isMappedToCurrentRequestPath(request))
+ {
+ log.debug("Applying Cache-Control HTTP header for resource '"
+ + httpRequest.getRequestURI() + "': " + getValue());
+
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ httpResponse.setHeader("Cache-Control", getValue());
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+}
Added: branches/community/Seam_2_2/src/main/org/jboss/seam/web/ConditionalAbstractResource.java
===================================================================
--- branches/community/Seam_2_2/src/main/org/jboss/seam/web/ConditionalAbstractResource.java (rev 0)
+++ branches/community/Seam_2_2/src/main/org/jboss/seam/web/ConditionalAbstractResource.java 2009-08-25 08:13:36 UTC (rev 11419)
@@ -0,0 +1,281 @@
+package org.jboss.seam.web;
+
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.util.Resources;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.net.URLConnection;
+import java.net.URL;
+import java.lang.management.ManagementFactory;
+
+/**
+ * Subclass this resource if you want to be able to send the right response automatically to
+ * any conditional <tt>GET</tt> or <tt>HEAD</tt> request. The typically usecase is as follows:
+ * <p/>
+ * <pre>
+ * public class MyResource extends ConditionalAbstractResource {
+ *
+ * public void getResource(final HttpServletRequest request, final HttpServletResponse response) {
+ * String resourceVersion = ... // Calculate current state as string
+ * or
+ * byte[] resourceVersion = ... // Calculate current state as bytes
+ *
+ * String resourcePath = ... // Get the relative (to servlet) path of the requested resource
+ *
+ * if ( !sendConditional(request,
+ * response,
+ * createdEntityTag(resourceVersion, false),
+ * getLastModifiedTimestamp(resourcePath) ) {
+ *
+ * // Send the regular resource representation with 200 OK etc.
+ * }
+ * }
+ * }
+ * </pre>
+ * <p/>
+ * Note that the <tt>getLastModifiedTimestamp()</tt> method is only supplied for convenience; it may not
+ * return what you expect as the "last modification timestamp" of the given resource. In many cases you'd
+ * rather calculate that timestamp yourself.
+ * <p/>
+ *
+ * @author Christian Bauer
+ */
+public abstract class ConditionalAbstractResource extends AbstractResource
+{
+
+ public static final String HEADER_LAST_MODIFIED = "Last-Modified";
+ public static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
+
+ public static final String HEADER_ETAG = "ETag";
+ public static final String HEADER_IF_NONE_MATCH = "If-None-Match";
+
+ private static final LogProvider log = Logging.getLogProvider(ConditionalAbstractResource.class);
+
+ /**
+ * Validates the request headers <tt>If-Modified-Since</tt> and <tt>If-None-Match</tt> to determine
+ * if a <tt>304 NOT MODIFIED</tt> response can be send. If that is the case, this method will automatically
+ * send the response and return <tt>true</tt>. If condition validation fails, it will not change the
+ * response and return <tt>false</tt>.
+ * <p/>
+ * Note that both <tt>entityTag</tt> and <tt>lastModified</tt> arguments can be <tt>null</tt>. The validation
+ * procedure and the outcome depends on what the client requested. If the client requires that both entity tags and
+ * modification timestamps be validated, both arguments must be supplied to the method and they must match, for
+ * a 304 response to be send.
+ * <p/>
+ * In addition to responding with <tt>304 NOT MODIFIED</tt> when conditions match, this method will also, if
+ * arguments are not <tt>null</tt>, send the right entity tag and last modification timestamps with the response,
+ * so that future requests from the client can be made conditional.
+ * <p/>
+ *
+ * @param request The usual HttpServletRequest for header retrieval.
+ * @param response The usual HttpServletResponse for header manipulation.
+ * @param entityTag An entity tag (weak or strong, in doublequotes), typically produced by hashing the content
+ * of the resource representation. If <tt>null</tt>, no entity tag will be send and if
+ * validation is requested by the client, no match for a NOT MODIFIED response will be possible.
+ * @param lastModified The timestamp in number of milliseconds since unix epoch when the resource was
+ * last modified. If <tt>null</tt>, no last modification timestamp will be send and if
+ * validation is requested by the client, no match for a NOT MODIFIED response will be possible.
+ * @return <tt>true</tt> if a <tt>304 NOT MODIFIED</tt> response status has been set, <tt>false</tt> if requested
+ * conditions were invalid given the current state of the resource.
+ * @throws IOException If setting the response status failed.
+ */
+ public boolean sendConditional(HttpServletRequest request,
+ HttpServletResponse response,
+ String entityTag, Long lastModified) throws IOException
+ {
+
+ String noneMatchHeader = request.getHeader(HEADER_IF_NONE_MATCH);
+ Long modifiedSinceHeader = request.getDateHeader(HEADER_IF_MODIFIED_SINCE); // Careful, returns -1 instead of null!
+
+ boolean noneMatchValid = false;
+ if (entityTag != null)
+ {
+
+ if (! (entityTag.startsWith("\"") || entityTag.startsWith("W/\"")) && !entityTag.endsWith("\""))
+ {
+ throw new IllegalArgumentException("Entity tag is not properly formatted (or quoted): " + entityTag);
+ }
+
+ // Always send an entity tag with the response
+ response.setHeader(HEADER_ETAG, entityTag);
+
+ if (noneMatchHeader != null)
+ {
+ noneMatchValid = isNoneMatchConditionValid(noneMatchHeader, entityTag);
+ }
+ }
+
+ boolean modifiedSinceValid = false;
+ if (lastModified != null)
+ {
+
+ // Always send the last modified timestamp with the response
+ response.setDateHeader(HEADER_LAST_MODIFIED, lastModified);
+
+ if (modifiedSinceHeader != -1)
+ {
+ modifiedSinceValid = isModifiedSinceConditionValid(modifiedSinceHeader, lastModified);
+ }
+
+ }
+
+ if (noneMatchHeader != null && modifiedSinceHeader != -1)
+ {
+ log.debug(HEADER_IF_NONE_MATCH + " and " + HEADER_IF_MODIFIED_SINCE + " must match");
+
+ // If both are received, we must not return 304 unless doing so is consistent with both header fields in the request!
+ if (noneMatchValid && modifiedSinceValid)
+ {
+ log.debug(HEADER_IF_NONE_MATCH + " and " + HEADER_IF_MODIFIED_SINCE + " conditions match, sending 304");
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return true;
+ }
+ else
+ {
+ log.debug(HEADER_IF_NONE_MATCH + " and " + HEADER_IF_MODIFIED_SINCE + " conditions do not match, not sending 304");
+ return false;
+ }
+ }
+
+ if (noneMatchHeader != null && noneMatchValid)
+ {
+ log.debug(HEADER_IF_NONE_MATCH + " condition matches, sending 304");
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return true;
+ }
+
+ if (modifiedSinceHeader != -1 && modifiedSinceValid)
+ {
+ log.debug(HEADER_IF_MODIFIED_SINCE + " condition matches, sending 304");
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return true;
+ }
+
+ log.debug("None of the cache conditions match, not sending 304");
+ return false;
+ }
+
+ protected boolean isNoneMatchConditionValid(String noneMatchHeader, String entityTag)
+ {
+ if (noneMatchHeader.trim().equals("*"))
+ {
+ log.debug("Found * conditional request, hence current entity tag matches");
+ return true;
+ }
+ String[] entityTagsArray = noneMatchHeader.trim().split(",");
+ for (String requestTag : entityTagsArray)
+ {
+ if (requestTag.trim().equals(entityTag))
+ {
+ log.debug("Found matching entity tag in request");
+ return true;
+ }
+ }
+ log.debug("Resource has different entity tag than requested");
+ return false;
+ }
+
+ protected boolean isModifiedSinceConditionValid(Long modifiedSinceHeader, Long lastModified)
+ {
+ if (lastModified <= modifiedSinceHeader)
+ {
+ log.debug("Resource has not been modified since requested timestamp");
+ return true;
+ }
+ log.debug("Resource has been modified since requested timestamp");
+ return false;
+ }
+
+ /**
+ * Tries to get last modification timestamp of the resource by obtaining
+ * a <tt>URLConnection</tt> to the file in the filesystem or JAR.
+ *
+ * @param resourcePath The relative (to the servlet) resource path.
+ * @return Either the last modified filestamp or if an error occurs, the JVM system startup timestamp.
+ */
+ protected Long getLastModifiedTimestamp(String resourcePath)
+ {
+ try
+ {
+ // Try to load it from filesystem or JAR through URLConnection
+ URL resourceURL = Resources.getResource(resourcePath, getServletContext());
+ if (resourceURL == null)
+ {
+ // Fall back to startup time of the JVM
+ return ManagementFactory.getRuntimeMXBean().getStartTime();
+ }
+ URLConnection resourceConn = resourceURL.openConnection();
+ return resourceConn.getLastModified();
+ }
+ catch (Exception ex)
+ {
+ // Fall back to startup time of the JVM
+ return ManagementFactory.getRuntimeMXBean().getStartTime();
+ }
+ }
+
+ /**
+ * Generates a (globally) unique identifier of the current state of the resource. The string will be
+ * hashed with MD5 and the hash result is then formatted before it is returned. If <tt>null</tt>,
+ * a <tt>null</tt> will be returned.
+ *
+ * @param hashSource The string source for hashing or the already hashed (strong or weak) entity tag.
+ * @param weak Set to <tt>true</tt> if you want a weak entity tag.
+ * @return The hashed and formatted entity tag result.
+ */
+ protected String createEntityTag(String hashSource, boolean weak)
+ {
+ if (hashSource == null) return null;
+ return (weak ? "W/\"" : "\"") + hash(hashSource, "UTF-8", "MD5") + "\"";
+ }
+
+ /**
+ * Generates a (globally) unique identifier of the current state of the resource. The bytes will be
+ * hashed with MD5 and the hash result is then formatted before it is returned. If <tt>null</tt>,
+ * a <tt>null</tt> will be returned.
+ *
+ * @param hashSource The string source for hashing.
+ * @param weak Set to <tt>true</tt> if you want a weak entity tag.
+ * @return The hashed and formatted entity tag result.
+ */
+ protected String createEntityTag(byte[] hashSource, boolean weak)
+ {
+ if (hashSource == null) return null;
+ return (weak ? "W/\"" : "\"") + hash(hashSource, "MD5") + "\"";
+ }
+
+ protected String hash(String text, String charset, String algorithm)
+ {
+ try
+ {
+ return hash(text.getBytes(charset), algorithm);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected String hash(byte[] bytes, String algorithm)
+ {
+ try
+ {
+ MessageDigest md = MessageDigest.getInstance(algorithm);
+ md.update(bytes);
+ BigInteger number = new BigInteger(1, md.digest());
+ StringBuffer sb = new StringBuffer("0");
+ sb.append(number.toString(16));
+ return sb.toString();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
Modified: branches/community/Seam_2_2/src/main/org/jboss/seam/web-2.2.xsd
===================================================================
--- branches/community/Seam_2_2/src/main/org/jboss/seam/web-2.2.xsd 2009-08-24 13:41:30 UTC (rev 11418)
+++ branches/community/Seam_2_2/src/main/org/jboss/seam/web-2.2.xsd 2009-08-25 08:13:36 UTC (rev 11419)
@@ -185,4 +185,15 @@
</xs:attribute>
</xs:attributeGroup>
+ <xs:element name="cache-control-filter">
+ <xs:annotation>
+ <xs:documentation>Sets the HTTP Cache-Control header</xs:documentation>
+ </xs:annotation>
+ <xs:complexType mixed="true">
+ <xs:attributeGroup ref="components:attlist.component"/>
+ <xs:attributeGroup ref="web:attlist.filter"/>
+ <xs:attribute name="value" type="components:string"/>
+ </xs:complexType>
+ </xs:element>
+
</xs:schema>
Modified: branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/testng.xml
===================================================================
--- branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/testng.xml 2009-08-24 13:41:30 UTC (rev 11418)
+++ branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/testng.xml 2009-08-25 08:13:36 UTC (rev 11419)
@@ -70,6 +70,7 @@
<test name="Seam Unit Tests: Resources and i8ln">
<classes>
<class name="org.jboss.seam.test.unit.InterpolatorTest"/>
+ <class name="org.jboss.seam.test.unit.web.ConditionalRequestTest" />
</classes>
</test>
Added: branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/web/ConditionalRequestTest.java
===================================================================
--- branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/web/ConditionalRequestTest.java (rev 0)
+++ branches/community/Seam_2_2/src/test/unit/org/jboss/seam/test/unit/web/ConditionalRequestTest.java 2009-08-25 08:13:36 UTC (rev 11419)
@@ -0,0 +1,228 @@
+package org.jboss.seam.test.unit.web;
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import static org.testng.Assert.assertEquals;
+import org.jboss.seam.mock.MockHttpSession;
+import org.jboss.seam.mock.EnhancedMockHttpServletRequest;
+import org.jboss.seam.mock.EnhancedMockHttpServletResponse;
+import org.jboss.seam.web.ConditionalAbstractResource;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletException;
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * @author Christian Bauer
+ *
+ */
+public class ConditionalRequestTest
+{
+ @Test
+ public void testNotModifiedOnlyETag() throws Exception
+ {
+
+ HttpSession session = new MockHttpSession();
+ EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest(session);
+ EnhancedMockHttpServletResponse response = new EnhancedMockHttpServletResponse();
+
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_NONE_MATCH, "\"1234\", \"5678\"");
+
+ ConditionalAbstractResource resource = new ConditionalAbstractResource()
+ {
+ public void getResource(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ if (!sendConditional(request, response, "\"5678\"", null))
+ {
+ response.sendError(HttpServletResponse.SC_OK);
+ }
+ }
+
+ public String getResourcePath()
+ {
+ return null;
+ }
+ };
+
+ resource.getResource(request, response);
+
+ assertEquals(response.getStatus(), HttpServletResponse.SC_NOT_MODIFIED);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_ETAG), "\"5678\"");
+
+ }
+
+ @Test
+ public void testModifiedOnlyETag() throws Exception
+ {
+
+ HttpSession session = new MockHttpSession();
+ EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest(session);
+ EnhancedMockHttpServletResponse response = new EnhancedMockHttpServletResponse();
+
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_NONE_MATCH, "\"123\", \"456\"");
+
+ ConditionalAbstractResource resource = new ConditionalAbstractResource()
+ {
+ public void getResource(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ if (!sendConditional(request, response, "\"5678\"", null))
+ {
+ response.sendError(HttpServletResponse.SC_OK);
+ }
+ }
+
+ public String getResourcePath()
+ {
+ return null;
+ }
+ };
+
+ resource.getResource(request, response);
+
+ assertEquals(response.getStatus(), HttpServletResponse.SC_OK);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_ETAG), "\"5678\"");
+ }
+
+ @Test
+ public void testNotModifiedOnlyLastModified() throws Exception
+ {
+
+ HttpSession session = new MockHttpSession();
+ EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest(session);
+ EnhancedMockHttpServletResponse response = new EnhancedMockHttpServletResponse();
+
+ final Long currentTime = new Date().getTime();
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_MODIFIED_SINCE, currentTime);
+
+ ConditionalAbstractResource resource = new ConditionalAbstractResource()
+ {
+ public void getResource(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ if (!sendConditional(request, response, null, currentTime))
+ {
+ response.sendError(HttpServletResponse.SC_OK);
+ }
+ }
+
+ public String getResourcePath()
+ {
+ return null;
+ }
+ };
+
+ resource.getResource(request, response);
+
+ assertEquals(response.getStatus(), HttpServletResponse.SC_NOT_MODIFIED);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_LAST_MODIFIED), currentTime);
+
+ }
+
+ @Test
+ public void testModifiedOnlyLastModified() throws Exception
+ {
+
+ HttpSession session = new MockHttpSession();
+ EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest(session);
+ EnhancedMockHttpServletResponse response = new EnhancedMockHttpServletResponse();
+
+ final Long currentTime = new Date().getTime();
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_MODIFIED_SINCE, currentTime);
+
+ ConditionalAbstractResource resource = new ConditionalAbstractResource()
+ {
+ public void getResource(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ if (!sendConditional(request, response, null, currentTime + 5000))
+ {
+ response.sendError(HttpServletResponse.SC_OK);
+ }
+ }
+
+ public String getResourcePath()
+ {
+ return null;
+ }
+ };
+
+ resource.getResource(request, response);
+
+ assertEquals(response.getStatus(), HttpServletResponse.SC_OK);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_LAST_MODIFIED), currentTime + 5000);
+
+ }
+
+ @Test
+ public void testNotModifiedETagLastModified() throws Exception
+ {
+
+ HttpSession session = new MockHttpSession();
+ EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest(session);
+ EnhancedMockHttpServletResponse response = new EnhancedMockHttpServletResponse();
+
+ final Long currentTime = new Date().getTime();
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_MODIFIED_SINCE, currentTime);
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_NONE_MATCH, "\"1234\", \"5678\"");
+
+ ConditionalAbstractResource resource = new ConditionalAbstractResource()
+ {
+ public void getResource(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ if (!sendConditional(request, response, "\"5678\"", currentTime))
+ {
+ response.sendError(HttpServletResponse.SC_OK);
+ }
+ }
+
+ public String getResourcePath()
+ {
+ return null;
+ }
+ };
+
+ resource.getResource(request, response);
+
+ assertEquals(response.getStatus(), HttpServletResponse.SC_NOT_MODIFIED);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_LAST_MODIFIED), currentTime);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_ETAG), "\"5678\"");
+
+ }
+
+ @Test
+ public void testModifiedETagLastModified() throws Exception
+ {
+
+ HttpSession session = new MockHttpSession();
+ EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest(session);
+ EnhancedMockHttpServletResponse response = new EnhancedMockHttpServletResponse();
+
+ final Long currentTime = new Date().getTime();
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_MODIFIED_SINCE, currentTime);
+ request.addHeader(ConditionalAbstractResource.HEADER_IF_NONE_MATCH, "\"1234\", \"5678\"");
+
+ ConditionalAbstractResource resource = new ConditionalAbstractResource()
+ {
+ public void getResource(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ if (!sendConditional(request, response, "\"5678\"", currentTime + 5000))
+ {
+ response.sendError(HttpServletResponse.SC_OK);
+ }
+ }
+
+ public String getResourcePath()
+ {
+ return null;
+ }
+ };
+
+ resource.getResource(request, response);
+
+ assertEquals(response.getStatus(), HttpServletResponse.SC_OK);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_LAST_MODIFIED), currentTime + 5000);
+ assertEquals(response.getHeader(ConditionalAbstractResource.HEADER_ETAG), "\"5678\"");
+
+ }
+}
15 years, 4 months
Seam SVN: r11418 - tags.
by seam-commits@lists.jboss.org
Author: manaRH
Date: 2009-08-24 09:41:30 -0400 (Mon, 24 Aug 2009)
New Revision: 11418
Added:
tags/JBPAPP_5_0-CR3/
Log:
tagged Seam EAP 5.0.0.CR3
Copied: tags/JBPAPP_5_0-CR3 (from rev 11417, branches/enterprise/JBPAPP_5_0)
15 years, 4 months