[jbossseam-issues] [JBoss JIRA] Created: (JBSEAM-3621) Support hot-deployment of instrumented wicket components
by Clint Popetz (JIRA)
Support hot-deployment of instrumented wicket components
--------------------------------------------------------
Key: JBSEAM-3621
URL: https://jira.jboss.org/jira/browse/JBSEAM-3621
Project: Seam
Issue Type: Patch
Reporter: Clint Popetz
Attached is a patch to add support for hot deployment of wicket components that have been instrumented by the wicket instrumentation ant task from JBSEAM-3505. That patch should be applied first to avoid conflicts.
The elements of this patch are:
* I need access to the HotDeploymentStrategy from the wicket classloader, but it's currently only exposed in the event context for the duration of startup. I've changed this to place it in the application context. I don't know if that's correct, but it seemed like a reasonable place to store it. So HotDeploymentStrategy now does this in its constructor.
* Initialization.redeploy now calls ServletLifecycle.beginReinitialization before createHotDeployment so that the app context exists. This puts createHotDeployment in the same contextual surroundings as its other invocation in Initialization.init().
* The WicketFilter needs to be re-initialized upon redeployment. So WicketFilter now delays initialization of the delegate (the @Unwrapped anonymous subclass of wicket's own WicketFilter) until the first actual request, and at each request it checks a stored initTime against Init.getTimestamp(). If they've changed, it re-inits. Also, I place WicketFilter within the HotDeployFilter via @Filter(within), so that all of this can work. This survives the absence of the HotDeployFilter, i.e. if you deploy without jboss-seam-debug.jar, SeamFilter ignores the missing within reference, and the WicketClassLoader just uses the thread's contextClassLoader for the parent of the instrumenting class loader.
* WicketClassLoader uses the HotDeploymentStrategy's classloader as the parent classloader, if it exists. This means that runtime-instrumented wicket components can reference hot-deployed wicket components, but not vice-versa, similar to how hot-deployable seam components can reference normally deployed components, but not vice-versa.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
17 years, 5 months
[jbossseam-issues] [JBoss JIRA] Created: (JBSEAM-3368) conversation id evaluated to null (natural conversations)
by Arron Ferguson (JIRA)
conversation id evaluated to null (natural conversations)
---------------------------------------------------------
Key: JBSEAM-3368
URL: https://jira.jboss.org/jira/browse/JBSEAM-3368
Project: Seam
Issue Type: Bug
Components: Core
Affects Versions: 2.0.3.CR1
Environment: Linux Ubuntu 7.10, Intel Pentium 4, 3GHz, 1 GB RAM, Tomcat 6.0.16
Reporter: Arron Ferguson
Priority: Blocker
If the user attempts to go to a page that is restricted based on what is in the pages.xml file, two things go wrong: 1) an exception is thrown (java.lang.IllegalStateException: conversation id evaluated to null: [name of natural conversation]), 2) the user can still view the page that is supposed to be restricted (i.e., using the restrict element in the pages.xml file).
Setup Instructions:
1.) Set up Tomcat 6.x
2.) Create web app project structure
3.) Use the following for your pages.xml file (copy/paste):
<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"
http-port="8080" https-port="8443"
no-conversation-view-id="/index.xhtml"
login-view-id="/index.xhtml">
<conversation name="regmem"
parameter-name="memberID"
parameter-value="#{memberreg.tempKey}"/>
<page view-id="*" scheme="http" />
<page view-id="/register.xhtml">
<description>Register Member: #{memberreg}</description>
<navigation from-action="#{memberreg.start}">
<begin-conversation join="true" conversation="regmem"/>
<redirect view-id="/register1.xhtml"/>
</navigation>
<navigation>
<rule if="#{identity.loggedIn}">
<redirect view-id="/memberadmin.xhtml"/>
</rule>
<rule if="#{memberreg.acceptedInformation}">
<redirect view-id="/register3.xhtml"/>
</rule>
<rule if="#{memberreg.agree}">
<redirect view-id="/register2.xhtml"/>
</rule>
<rule if="#{memberreg.started}">
<redirect view-id="/register1.xhtml"/>
</rule>
</navigation>
</page>
<page view-id="/register1.xhtml" conversation-required="true"
conversation="regmem">
<description>Register Member: #{memberreg}</description>
<restrict>#{memberreg.started}</restrict>
<navigation from-action="#{memberreg.agreeToLicense}">
<redirect view-id="/register2.xhtml"/>
</navigation>
<navigation from-action="#{memberreg.cancel}">
<end-conversation/>
<redirect view-id="/index.xhtml"/>
</navigation>
<navigation>
<rule if="#{identity.loggedIn}">
<redirect view-id="/memberadmin.xhtml"/>
</rule>
<rule if="#{memberreg.acceptedInformation}">
<redirect view-id="/register3.xhtml"/>
</rule>
<rule if="#{memberreg.agree}">
<redirect view-id="/register2.xhtml"/>
</rule>
</navigation>
</page>
<page view-id="/register2.xhtml" conversation-required="true"
conversation="regmem">
<description>Register Member: #{memberreg}</description>
<restrict>#{memberreg.agree}</restrict>
<navigation from-action="#{memberreg.next}">
<rule if="#{memberreg.readyToConfirm}">
<redirect view-id="/register3.xhtml"/>
</rule>
<rule if="#{not memberreg.readyToConfirm}">
<redirect view-id="/register2.xhtml"/>
</rule>
</navigation>
<navigation>
<rule if="#{identity.loggedIn}">
<redirect view-id="/memberadmin.xhtml"/>
</rule>
<rule if="#{memberreg.acceptedInformation}">
<redirect view-id="/register3.xhtml"/>
</rule>
</navigation>
</page>
<page view-id="/register3.xhtml" conversation-required="true"
conversation="regmem">
<description>Register Member: #{memberreg}</description>
<restrict>#{memberreg.readyToConfirm}</restrict>
<navigation from-action="#{memberreg.acceptInformation}">
<redirect view-id="/register4.xhtml"/>
</navigation>
<navigation from-action="#{memberreg.editInformation}">
<redirect view-id="/register2.xhtml"/>
</navigation>
<navigation>
<rule if="#{identity.loggedIn}">
<redirect view-id="/memberadmin.xhtml"/>
</rule>
</navigation>
</page>
<page view-id="/register4.xhtml" conversation-required="true"
conversation="regmem">
<description>Register Member: #{memberreg}</description>
<restrict>#{memberreg.acceptedInformation}</restrict>
<navigation from-action="#{memberreg.end}">
<end-conversation before-redirect="false"/>
<redirect view-id="/index.xhtml"/>
</navigation>
</page>
<!-- START EXCEPTIONS -->
<exception class="org.jboss.seam.security.NotLoggedInException" log="false">
<redirect view-id="/index.xhtml">
<message severity="warn">Your session ended or expired.</message>
</redirect>
</exception>
<exception class="org.jboss.seam.security.AuthorizationException" log="false">
<end-conversation/>
<redirect view-id="/index.xhtml">
<message severity="warn">You are not authorized.</message>
</redirect>
</exception>
<!-- END EXCEPTIONS -->
</pages>
4.) Create two Java classes (registration bean and POJO):
Registration Bean:
package com.test;
import javax.ejb.Remove;
import javax.persistence.Column;
import javax.persistence.NoResultException;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.EntityManager;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.faces.Renderer;
import static org.jboss.seam.ScopeType.CONVERSATION;
@Scope(CONVERSATION)
@Name("memberreg")
public class MemberRegistrationAction implements Serializable
{
private static long tempKey = 0;
@Out(required = false) @In(required = false)
private Member newMember;
@In(create = true)
private Renderer renderer;
private boolean started = false;
private boolean agree = false;
private boolean acceptedInformation = false;
private boolean readyToConfirm = false;
private boolean stillNeedsToEdit = false;
private String confirm = "";
public String getConfirm() { return confirm; }
public void setConfirm(String confirm) { this.confirm = confirm; }
public long getTempKey() { return tempKey; }
public void setTempKey(long tempKey) { this.tempKey = tempKey; }
public Member getNewMember() { return newMember; }
/////////////////////////////////////////////
// CONVERSATION METHODS
/////////////////////////////////////////////
public void start()
{
newMember = new Member();
if(tempKey >= Long.MAX_VALUE)
{
tempKey = 0;
}
tempKey++;
started = true;
}
public void agreeToLicense() { agree = true; }
public void cancel()
{
started = false;
agree = false;
acceptedInformation = false;
readyToConfirm = false;
stillNeedsToEdit = false;
}
public void next() { readyToConfirm = this.verify(); }
private boolean verify() {
return true; // test purposes, always true
}
public void acceptInformation()
{
acceptedInformation = true;
stillNeedsToEdit = false;
this.complete();
}
public void editInformation()
{
stillNeedsToEdit = true;
acceptedInformation = false;
}
private void complete() {
; // write to JPA/Hibernate
}
public void end() {
; // something, something, something, dark side
}
/////////////////////////////////////////////
public boolean isStarted() { return started; }
public boolean isAgree() { return agree; }
public boolean isAcceptedInformation() { return acceptedInformation; }
public boolean isReadyToConfirm() { return readyToConfirm; }
public boolean isStillNeedsToEdit() { return stillNeedsToEdit; }
public void destroy()
{
started = false;
agree = false;
acceptedInformation = false;
readyToConfirm = false;
stillNeedsToEdit = false;
}
}
POJO:
package com.test;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.jboss.seam.annotations.Name;
@Entity @Name("member") @Table(name="member")
public class Member implements Serializable {
@Id
@GeneratedValue
@Column(name = "id")
private long id = -1;
@NotNull
@Length(min=2, max=20, message="Must be between 2 and 20 chars long")
@Column(name = "lastname")
private String lastName;
@NotNull
@Length(min=2, max=20, message="Must be between 2 and 20 chars long")
@Column(name = "firstname")
private String firstName;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
@Override
public String toString() { return firstName + " " + lastName; }
}
5.) Create XHTML files (template, index, register1 - register4):
///////////////////////////////////
template.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" >
<head>
<title>something.com</title>
</head>
<body>
<div>
<h:messages globalOnly="true"/><br/><br/>
<ui:insert name="maincontent">
</ui:insert>
</div>
</body>
</html>
///////////////////////////////////
index.html:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:s="http://jboss.com/products/seam/taglib">
<!-- <ui:composition template="./template.xhtml"> -->
<ui:composition template="./template.xhtml">
<ui:define name="maincontent">
<s:link view="/register.html" value="click here to register" propagation="none"/>
</ui:define>
</ui:composition>
</html>
///////////////////////////////////
register.html
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:s="http://jboss.com/products/seam/taglib">
<ui:composition template="./template.xhtml">
<ui:define name="maincontent">
<p>Click to start natural conversation:</p>
<h:form id="testform">
<h:outputText value="Click: "/>
<h:commandButton value="Register" action="#{memberreg.start}">
<s:conversationName value="regmem"/>
<s:conversationPropagation type="join"/>
</h:commandButton>
</h:form>
</ui:define>
</ui:composition>
</html>
///////////////////////////////////
register1.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:s="http://jboss.com/products/seam/taglib" >
<ui:composition template="./template.xhtml">
<ui:define name="maincontent">
<h:form id="agreeform">
<h:commandButton id="agreebut1" value="Agree"
action="#{memberreg.agreeToLicense}">
<s:conversationName value="regmem"/>
<s:conversationPropagation type="join"/>
</h:commandButton>
<br/><p>Click cancel to kill the natural conversation early</p>
<h:commandButton id="disagreebut1" value="Disagree"
action="#{memberreg.cancel}">
<s:conversationName value="regmem"/>
<s:conversationPropagation type="end"/>
</h:commandButton>
</h:form>
</ui:define>
</ui:composition>
</html>
///////////////////////////////////
register2.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:s="http://jboss.com/products/seam/taglib" >
<ui:composition template="./template.xhtml">
<ui:define name="maincontent">
<h:form id="formfields">
<p>Content inserted for testing purposes when this button clicked:</p>
<h:commandButton id="next" value="Next" action="#{memberreg.next}">
<s:conversationName value="regmem"/>
<s:conversationPropagation type="join"/>
</h:commandButton>
</h:form>
</ui:define>
</ui:composition>
</html>
///////////////////////////////////
register3.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:s="http://jboss.com/products/seam/taglib" >
<ui:composition template="./template.xhtml">
<ui:define name="maincontent">
<h:form id="formfields" rendered="#{not identity.loggedIn}">
<h:commandButton id="editinfo" value="Edit Information"
action="#{memberreg.editInformation}">
<s:conversationName value="regmem"/>
<s:conversationPropagation type="join"/>
</h:commandButton>
     
<h:commandButton id="confirmreg" value="Confirm Registration"
action="#{memberreg.acceptInformation}">
<s:conversationName value="regmem"/>
<s:conversationPropagation type="join"/>
</h:commandButton>
</h:form>
</ui:define>
</ui:composition>
</html>
///////////////////////////////////
register4.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:s="http://jboss.com/products/seam/taglib" >
<ui:composition template="./template.xhtml">
<ui:define name="maincontent">
<p>Click back to finish natural conversation.</p>
<s:link value="Back to home." action="#{memberreg.end}"
propagation="end"/>
</ui:define>
</ui:composition>
</html>
6.) Use the following JARs for your web app (for running inside of Tomcat 6):
activation.jar
antlr.jar
asm.jar
cglib.jar
commons-beanutils.jar
commons-codec-1.3.jar
commons-collections.jar
commons-digester.jar
commons-lang.jar
commons-logging.jar
DA.jar
dom4j.jar
ejb-api.jar
filelist.txt
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-entitymanager.jar
hibernate.jar
hibernate-search.jar
hibernate-validator.jar
javassist.jar
jboss-archive-browsing.jar
jboss-el.jar
jboss-seam-debug.jar
jboss-seam-ioc.jar
jboss-seam.jar
jboss-seam-mail.jar
jboss-seam-ui.jar
jsf-api.jar
jsf-facelets.jar
jsf-impl.jar
jstl.jar
jta.jar
lucene-core.jar
mail.jar
persistence-api.jar
richfaces-api.jar
richfaces-impl.jar
richfaces-ui.jar
spring.jar
urlrewrite-3.1.0.jar
7.) (Optional) Set up facelets but you may also want to make the default extension html:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
Steps to reproduce bug:
1.) Start web app inside of Tomcat 6
2.) using your browser's URL text field, type in the name of a register1.html, register2.html, or register3.html. At this point your web app will generate an exception stack which will be caused by:
java.lang.IllegalStateException: conversation id evaluated to null:
The conversation is evaluated to null. Since conversations are a layer on top of sessions, the same behavior is expected which is a faces message purporting of no conversation existing and a redirect to the URL specified in the pages.xml attribute no-conversation-view-id="/index.xhtml" (so in this case index.xhtml page). It should not allow the user to see the page and generate exceptions.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
17 years, 5 months
[jbossseam-issues] [JBoss JIRA] Created: (JBSEAM-3622) SFSB not removed from session when temporary conversation ends
by Nikolay Elenkov (JIRA)
SFSB not removed from session when temporary conversation ends
--------------------------------------------------------------
Key: JBSEAM-3622
URL: https://jira.jboss.org/jira/browse/JBSEAM-3622
Project: Seam
Issue Type: Bug
Components: Core
Affects Versions: 2.1.0.GA, 2.0.3.CR1
Environment: JBoss 4.2.2, Seam 2.0.3.CR1
Reporter: Nikolay Elenkov
I came across this while checking my app for session leaks. I have a simple listeners that dumps session attributes on every add/remove/replace.
When I end a conversation, all entities are removed from the session, as expected. However, manager components (SFSB's) are left over. Repeatedly starting and ending a conversation results in something like (17, 18, 19 have ended, all other attributes for those conversations have been removed from session; 20 is active):
20:11:12,440 INFO [STDOUT] org.jboss.seam.CONVERSATION#17$userManager
20:11:12,440 INFO [STDOUT] org.jboss.seam.CONVERSATION#18$userManager
20:11:12,440 INFO [STDOUT] org.jboss.seam.CONVERSATION#19$userManager
20:11:12,440 INFO [STDOUT] org.jboss.seam.CONVERSATION#20$userManager
20:11:12,440 INFO [STDOUT] org.jboss.seam.CONVERSATION#20$user
I stepped through this with the debugger, and it seems that SFSB's are not removed if the conversation is a temporary one.
Here's what (I think) happens:
1. Conversation ended by @End or pages.xml
2. SFSB's @Remove @Destroy destroy() method is called
3. RemoveInterceptor calls ServerConversationContext#remove(). That results in the component's name being added to ServerConversationContext#removals.
4. When ServerConversationContext#flush() is called, names in the removals list are not actually removed from the session, because the conversation is temporary (see *** below)
from ServerConversationContext.java:
public void flush()
{
boolean longRunning = !isCurrent() || Manager.instance().isLongRunningConversation();
if ( longRunning )
{
// ....
}
else
{
//TODO: for a pure temporary conversation, this is unnecessary, optimize it
// *** Here: getNamesFromSession does not include removals, so they are left over
// Should probably be like this:
// START
for (String name: removals) {
session.remove(getKey(name));
}
removals.clear();
// END
for ( String name: getNamesFromSession() )
{
session.remove( getKey(name) );
}
}
}
private Set<String> getNamesFromSession()
{
HashSet<String> results = new HashSet<String>();
String prefix = getPrefix(getId());
for (String name: session.keySet()) {
if (name.startsWith(prefix)) {
name = name.substring(prefix.length());
if (!removals.contains(name)) { // *** Here: name not added to results if in the removals list
results.add(name);
}
}
}
return results;
}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
17 years, 5 months
[jbossseam-issues] [JBoss JIRA] Created: (JBSEAM-3593) itext example throws a ResourceNotFoundException when you first navigate to the page
by Jay Balunas (JIRA)
itext example throws a ResourceNotFoundException when you first navigate to the page
-------------------------------------------------------------------------------------
Key: JBSEAM-3593
URL: https://jira.jboss.org/jira/browse/JBSEAM-3593
Project: Seam
Issue Type: Bug
Components: Examples
Affects Versions: 2.1.0.CR1
Environment: JDK 6
Fedora 8
AS 5 CR2
Reporter: Jay Balunas
Priority: Minor
Fix For: 2.1.1.CR1
itext example throws a ResourceNotFoundException when you first navigate to the page, but the page and links still function as expected.
14:38:51,701 ERROR [[Faces Servlet]] Servlet.service() for servlet Faces Servlet threw exception
org.ajax4jsf.resource.ResourceNotFoundException: Resource not registered : org/richfaces/renderkit/html/scripts/skinning.js.seam
at org.ajax4jsf.resource.ResourceBuilderImpl.getResource(ResourceBuilderImpl.java:397)
at org.ajax4jsf.resource.ResourceBuilderImpl.getResourceForKey(ResourceBuilderImpl.java:341)
at org.ajax4jsf.resource.InternetResourceService.serviceResource(InternetResourceService.java:152)
at org.ajax4jsf.resource.InternetResourceService.serviceResource(InternetResourceService.java:141)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:500)
at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:51)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:93)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:325)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:601)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
17 years, 5 months
[jbossseam-issues] [JBoss JIRA] Created: (JBSEAM-3594) Wicket instrumentation fails on inherited components
by Clint Popetz (JIRA)
Wicket instrumentation fails on inherited components
----------------------------------------------------
Key: JBSEAM-3594
URL: https://jira.jboss.org/jira/browse/JBSEAM-3594
Project: Seam
Issue Type: Bug
Affects Versions: 2.1.0.CR1
Reporter: Clint Popetz
Attachments: seam-wicket-inheritance.patch
Most wicket configuration is done in the constructor, and much component re-use takes place through page and panel inheritance.
The generic case in question is:
class base {
public base() {
add("id",overriddenMethod());
}
public Component overriddenMethod() { ... }
}
public class sub extends base {
public sub() {
super();
...
}
public Component overriddenMethod() { ... } l
}
The subclass WicketHandler initializer won't have run by the time the overriddenMethod has been invoked, so its wicketHandler instance will be null, and the overriddenMethod will throw a null pointer exception. What I've done is to make the javassist preamble/postamble avoid that NPE by checking to make sure the handler is not null before doing anything. Since WicketHandler.create() uses the runtime class of the target component, the interception that happens for the base.<init> in the above example will ensure that injections happen for the subclass before the overridden method is called.
This check also has to happen when walking the enclosedInstance injections of any class in BijectionInterceptor.injectEnclosingInstances(), because if the above overriddenMethod() were to create an instance of an anonymous inner class, the enclosing instance's handler field will be null.
Three more bugs related to inheritance in this patch :
(1) I made WicketComponent.scan() check superclasses, so that it injects for the superclasses as well . This would be needed, for example, if an overridden method referred to a visible injected field in a superclass.)
(2) I've taken out the check that made the instrumentor not instrument abstract classes. I can't think of a good reason for that check, and it kept me from having abstract superclasses with injections.
(3) If you override a method, you get an infinite loop, because the synthetic method where the actual code lives will be generated with the same name in both super and subclass, and one will override the other, so that when sub.fooUNIQUE() calls base.foo(), it will call base.fooUNIQUE(), which will be a virtual call to sub.fooUNIQUE(). So I made the synthetic method private, which means it gets an invokespecial instead of an invokevirtual.
(4) A similar problem with constructors...the preamble was calling getClass().getDeclaredConstructor(), but it now refers directly to the class in question, so that if a subclass has a constructor with the same signature, you don't get an infinite loop when the parent class tries to find its own constructor.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
17 years, 5 months