Aryeh,

On 9/12/23 12:42, Aryeh Friedman wrote:
On Tue, Sep 12, 2023 at 11:42 AM Christopher Schultz
<ch...@christopherschultz.net> wrote:

Aryeh,

On 9/11/23 10:05, Aryeh Friedman wrote:
On Mon, Sep 11, 2023 at 9:47 AM Christopher Schultz
<ch...@christopherschultz.net> wrote:

Aryeh,

On 9/9/23 19:36, Aryeh Friedman wrote:
On Sat, Sep 9, 2023 at 1:23 PM Mark Thomas <ma...@apache.org> wrote:

On 09/09/2023 11:52, Aryeh Friedman wrote:
Every other jsp in my webapp (and other webapps on the same tomcat
instance [9.0.75]) works and I am using a the default container but as
curl/catalina.out show BasePage is *NEVER* being called (either the
_jspService() or the getX()):

How have you configured your JSP(s) to use this alternative base class?

sudo cat /usr/local/apache-tomcat-9.0/webapps/tlaitc-dashboard-1a1/index.jsp
<!-- Copyright (C) 2023 TLAITC and contributors -->
<%@page extends="dashboard.web.pages.BasePage"%>
hi x is ${x}

Output shown in log (sorry for not including the JSP the first time)
but to make it easier to find the output is "hi x is " when it should
be "hi x is 123234"... as you notice there are zero errors/warning in
catalina but there is none of the println's also... so the only thing
I can surmise is BasePage is never being called <%@page
extends="dashboard.web.pages.BasePage"%> somehow failed but I have
verified that correct spelling several times and also verified any
syntextual errors [including the contents of the string literal] will
show up in catalina.out (i.e. wrong class name is logged as an error)

Your _jspService method in your base class will never be called, because
it is overridden by the auto-generated class for your JSP, which does
not call super._jspService.

I do not believe that this:

Hi X is ${x}

...will result in this.getX() being called from the JSP. References in
EL ${...} expressions will be resolved against the PageContext (and
other wider contexts), not against the JSP class currently executing.

If you want to call this.getX() then you will need to do this:

Hi X is <% getX() %>

I wouldn't bother messing-around with class hierarchies in JSP. It
usually doesn't get you much but almost always requires you to bind
yourself very closely with the specific implementation of the JSP engine.

It would be far better to use typical MVC-style development where a
servlet (or similar) handles the real work of the request, possibly
including writing a value of "x" to the request attributes. Then forward
your request to your JSP to produce the response content. This will be
much more straightforward and you will have fewer problems like this,
where expected behavior is confused by all the magic that JSP provides.

Thanks but I have a very specific use case which the following working
example below should make more clear:

<!-- Copyright (C) 2023 TLAITC and contributors -->
<%@page import="dashboard.web.page.Page"%>
<%
          // THIS WOULD NOT BE NEEDED if <%@page extends="..."%> worked
          //
          // for now we don't need to keep the page object just
          // the setAttributes in our ctx
          new Page(pageContext);
%>

<html>
<head>
          <%@include file="/widgets/scripts/scripts.jsp"%>
</head>
<body>
           <jsp:include page="${pagePath}"/>
</body>
</html>

and the Page class:

package dashboard.web.page;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.PageContext;

import org.petitecloud.util.PetiteCloudNullException;

// making this extend the right subclass plus working page
extends="...." would mean zero in-line Java
// Copyright (C) 2023 TLAITC and contributors
public class Page
{
      public Page(PageContext ctx)
      {
          _dbc_construction(ctx);

          this.ctx=ctx;

          HttpServletRequest req=(HttpServletRequest) ctx.getRequest();
          String[] parts=req.getRequestURI().split("/");
          int split=2;

          if(parts[0].equals("http:"))
              split+=2;

          name="";
          for(int i=split;i<parts.length;i++)
              name+="/"+parts[i];

          if(name.length()==0)
              name="/index.jsp";

          // we can safely asssume all valid requests will end with
          // .jsp at this point
          name=name.substring(1,name.length()-".jsp".length());
          path="/content/"+name+"/main.jsp";

          ctx.setAttribute("pagePath",path);
      }

      // only used in testing
      public Page(String name)
      {
          this.name=name;
      }

      public String getName()
      {
          return name;
      }

      public String getPath()
      {
          return path;
      }

      public PageContext getPageContext()
      {
          return ctx;
      }

      @Override
      public String toString()
      {
          return name;
      }

      @Override
      public int hashCode()
      {
          return name.hashCode();
      }

      @Override
      public boolean equals(Object o)
      {
          if(o==null||!o.getClass().equals(getClass()))
              return false;

          Page other=(Page) o;

          return name.equals(other.name);
      }

      private String name;
      private String path;
      private PageContext ctx;

      // ----- # DBC # -------------------------------------------

      private void _dbc_construction(PageContext ctx)
      {
          if(ctx==null)
              throw new PetiteCloudNullException("ctx is null");
      }
}

So all I am attempting to do is write it like this (get rid of the
last remaining in-line java but not be forced to use tag instead of
${} either):

<!-- Copyright (C) 2023 TLAITC and contributors -->
<%@page extends="dashboard.web.page.Page"%>

<html>
<head>
          <%@include file="/widgets/scripts/scripts.jsp"%>
</head>
<body>
           <jsp:include page="${pagePath}"/>
</body>
</html>

Side note I am currently adding user detection to the above page class
to that it can auto-enforce ACL's

I'm not sure I understand the point of the whole exercise. Nothing you
have in the PageContext class constructor cannot be done from within the
JSP itself, or -- better yet -- in an <%include> used by as many pages
as you want. *OR* ... you could do it in a Filter and apply it to all
requests, storing the information in the request attributes, which is
much more standard than directly modifying the page context.

The idea is to avoid any custom entries in web.xml (which filters
require)

This is not entirely true, and seems to be an arbitrary requirement. The application is configured via web.xml. Why disallow any configuration in web.xml?

and the entire point is this is a top level template and
future versions will provide a number of standard setAttriburtes that
expose different things like the logged in user.

Yeah, you are welcome to your own opinion, but everything you describe sounds like "we want to use JSPs for everything and not write Java code" and honestly what you need is plain-old Java code for this stuff.

In general I try to avoid relying on any given low level framework
then is needed and doing this ties us more to servlet-api then makes
sense (i.e. it is not very portable to non-monolithic servers like
tomcat but it is portable if you avoid stuff like web.xml as
possible).
I would argue the /absolute opposite/: using web.xml for its intended purpose is exactly the correct way to avoid tying yourself to a specific server. If you are trying to avoid bindings to the Servlet API but in exchange you are binding to Tomcat, I see that as a net-negative: the Servlet API is a better choice than Tomcat if you have to pick one to bind to.

There are frameworks which you can use that do not require you do bind your application to either Tomcat OR the servlet-api (I'm thinking of Apache Struts 2, for example), but you do have to give up some small bits of capabilities because really advanced stuff requires binding to those APIs.

Writing JSPs is already very very VERY tightly binding your application to the Servlet API. I don't understand this requirement at a very fundamental level.

The answer to the question "how do I write my application in a way that avoids binding to (e.g) the servlet API" is "use a framework which insulates you and the application from that API". There are some (again, thinking of Apache Struts 2, here) that don't even require that you bind your code to THEIR APIs. You write POJOs and some configuration to glue it all together. No compile-time dependencies. You can port your application to Swing/JavaFX if you feel like going down that route, and only the GUI glue itself needs to be "bound" to AWT/Swing/JavaFX/whatever. Your core application code doesn't need any of that.

The stuff the Servlet Spec provides should be thought of as glue that allows your core application (without Servlet API bindings) to be accessible through a web-based interface. But you appear to be trying to implement your core application in JSP which is counter-intuitive to me and seems to be the opposite of your goal to be API-independent.

Case in point for performance reasons I wrote a server called
babyHttp that is an extremely stripped down API endpoint oriented
server that does not use web.xml or anything of the kind (purposely
make it so the only linkage between modules is actual Java source
code).   Keep in mind HIPAA is a requirement here.
I do not know why your "case in point" is relevant. Sure, you were able to create a toy HTTP server but anybody who has read an introductory Java programming book can probably copy such a thing out of the examples from that same book. HIPAA is a red herring, other than you'd better be careful about implementing your own HTTP endpoint since it's very easy to do it incorrectly.

-chris

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to