jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.85k stars 1.91k forks source link

Jetty 12 Shared scheduler not started #11097

Open wise-coders opened 9 months ago

wise-coders commented 9 months ago

I am executing

super( new InetSocketAddress("127.0.0.1", port));
        final ContextHandlerCollection handlers = new ContextHandlerCollection( true );
        setHandler(handlers);
        // ACCEPT ONLY CONNECTIONS FROM LOCALHOST
        try ( ServerConnector sc = new ServerConnector(this)) {
            sc.setPort(port);
            sc.setHost("localhost");
            setConnectors(new Connector[]{sc});

            this.contextHandler = new ServletContextHandler("/", ServletContextHandler.SESSIONS );
            contextHandler.setHandler( handlers );
            contextHandler.setBaseResource(ResourceFactory.of( this ).newResource(new File(Sys.installForm).toPath()));
            handlers.addHandler( contextHandler );

            contextHandler.addServlet( new ServletHolder( new InternalImageServlet()), "/" + FormUtil.LOCAL_IMAGES + "*");
            contextHandler.addServlet( new ServletHolder( new DbImageServlet()), "/" + FormUtil.DATABASE_IMAGES + "*");

            // FILES ARE SERVED HERE
            ServletHolder holderDef = new ServletHolder( "default", DefaultServlet.class);
            holderDef.setInitParameter("dirAllowed", "false");
            contextHandler.addServlet(holderDef, "/");
            contextHandler.start();
        }

and getting

ava.lang.IllegalStateException: Shared scheduler not started
    at org.eclipse.jetty.session.HouseKeeper.startScavenging(HouseKeeper.java:115)
    at org.eclipse.jetty.session.HouseKeeper.setIntervalSec(HouseKeeper.java:200)
    at org.eclipse.jetty.session.HouseKeeper.doStart(HouseKeeper.java:84)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93)
    at org.eclipse.jetty.session.DefaultSessionIdManager.doStart(DefaultSessionIdManager.java:329)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93)
    at org.eclipse.jetty.session.AbstractSessionManager.doStart(AbstractSessionManager.java:293)
    at org.eclipse.jetty.ee10.servlet.SessionHandler.doStart(SessionHandler.java:450)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:171)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:121)
    at org.eclipse.jetty.server.Handler$Abstract.doStart(Handler.java:468)
    at org.eclipse.jetty.server.handler.ContextHandler.lambda$doStart$0(ContextHandler.java:638)
    at org.eclipse.jetty.server.handler.ContextHandler$ScopedContext.call(ContextHandler.java:1141)
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:638)
    at org.eclipse.jetty.ee10.servlet.ServletContextHandler.startContext(ServletContextHandler.java:1312)
    at org.eclipse.jetty.ee10.servlet.ServletContextHandler.lambda$doStart$0(ServletContextHandler.java:1042)
    at org.eclipse.jetty.server.handler.ContextHandler$ScopedContext.call(ContextHandler.java:1147)
    at org.eclipse.jetty.ee10.servlet.ServletContextHandler.doStart(ServletContextHandler.java:1039)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93)
    at com.wisecoders.dbs.forms.play.html.servlets.JettyServer.<init>(JettyServer.java:53)
    at com.wisecoders.dbs.forms.play.html.servlets.JettyServer.init(JettyServer.java:61)
    at com.wisecoders.dbs.forms.play.html.servlets.FxFormJettyTask.call(FxFormJettyTask.java:39)
    at com.wisecoders.dbs.forms.play.html.servlets.FxFormJettyTask.call(FxFormJettyTask.java:23)
    at javafx.concurrent.Task$TaskCallable.call(Task.java:1426)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
    at java.base/java.lang.Thread.run(Thread.java:1589)

Maybe I do something wrong due migration from previous versions?

sbordet commented 9 months ago

@wise-coders you don't show all your code, but I assume the code you show is a subclass of org.eclipse.jetty.server.Server.

If that's the case, then:

remove this line, which is wrong:

contextHandler.setHandler( handlers );

since 2 lines below you call handlers.addHandler( contextHandler ); which is correct.

Then, you need to start the whole Server instance, not just the ContextHandler, at the last line.

Then, the try-finally block is wrong, since it will close the ServerConnector after the last line.

Finally, you don't need the ContextHandlerCollection if you only have one ContextHandler.

In summary, your code can be better be written in this way:

Server server = new Server();

ServerConnector sc = new ServerConnector(server);
sc.setPort(port);
sc.setHost("localhost");
server.addConnector(sc);

ServletContextHandler contextHandler = new ServletContextHandler("/", ServletContextHandler.SESSIONS);
server.setHandler(contextHandler);

contextHandler.setBaseResource(ResourceFactory.of( server ).newResource(new File(Sys.installForm).toPath()));
contextHandler.addServlet( new ServletHolder( new InternalImageServlet()), "/" + FormUtil.LOCAL_IMAGES + "*");
contextHandler.addServlet( new ServletHolder( new DbImageServlet()), "/" + FormUtil.DATABASE_IMAGES + "*");

ServletHolder holderDef = new ServletHolder( "default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "false");
contextHandler.addServlet(holderDef, "/");

server.start();
wise-coders commented 9 months ago

Thank you very much for your help. This works. I still have a problem with the local files, they seem not to be served. The variable Sys.installForm is an URL pointing to the local folder where this files are stored. Something similar worked in the old version of Jetty. What could be wrong?

            contextHandler.setBaseResource(ResourceFactory.of(this).newResource(Sys.installForm));
            ServletHolder holderDef = new ServletHolder( "default", DefaultServlet.class);
            holderDef.setInitParameter("dirAllowed", "false");
            contextHandler.addServlet(holderDef, "/");
sbordet commented 9 months ago

You don't specify the Jetty version you are using.

Would be great if you can detail exactly what the problem is. Do you get an error? An exception on server side? A 404? What is the URI you are asking for? Are you sure the file is there? Etc.

Too little information to help you.

wise-coders commented 9 months ago

I use:

implementation 'org.eclipse.jetty:jetty-server:12.0.5'
implementation 'org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.5'

The request is

http://localhost:8087/css/forms.css

returns

HTTP ERROR 404 Not Found
URI:    http://localhost:8087/css/forms.css
STATUS: 404
MESSAGE:    Not Found

The path c:\work\dbschema\build\resources\main\forms\css\forms.css exists, Sys.installForms=file:/C:/work/dbschema/build/resources/main/forms/

sbordet commented 9 months ago

The problem could be the file:/ initial part of the URI of Sys.installForms. I don't have Windows available, can you try setting the URI to file:///C:work/dbschema/build/resources/main/forms/? Note the triple slash after the scheme.

wise-coders commented 9 months ago

Unfortunately it does not work. I reverted to:

    implementation 'org.eclipse.jetty:jetty-server:11.0.19'
    implementation 'org.eclipse.jetty:jetty-servlet:11.0.19'

and it works fine with this code:

                super( new InetSocketAddress("127.0.0.1", port));
        // ACCEPT ONLY CONNECTIONS FROM LOCALHOST
        try ( ServerConnector sc = new ServerConnector(this)) {
            sc.setPort(port);
            sc.setHost("localhost");
            setConnectors(new Connector[]{sc});

            this.contextHandler = new ServletContextHandler( null,"/", ServletContextHandler.SESSIONS );
            this.setHandler( contextHandler );

            contextHandler.setBaseResource( Resource.newResource(new File(Sys.installForm)));
            contextHandler.addServlet( new ServletHolder( new InternalImageServlet()), "/" + FormUtil.LOCAL_IMAGES + "*");
            contextHandler.addServlet( new ServletHolder( new DbImageServlet()), "/" + FormUtil.DATABASE_IMAGES + "*");

            // FILES ARE SERVED HERE
            ServletHolder holderDef = new ServletHolder( "default", DefaultServlet.class);
            holderDef.setInitParameter("dirAllowed", "false");
            contextHandler.addServlet(holderDef, "/");
        }
joakime commented 9 months ago

The path c:\work\dbschema\build\resources\main\forms\css\forms.css exists, Sys.installForms=file:/C:/work/dbschema/build/resources/main/forms/

Is there a link (hardlink / symlink / etc) present in that path? If so, then it's considered an alias and then you need to enable the appropriate AliasChecker to allow it (which also reduces your security level).

wise-coders commented 9 months ago

There is no link in the path.

joakime commented 9 months ago

Run this code with Jetty 12 and tell us the output.

import java.nio.file.Path;
import java.nio.file.Files;
import org.eclipse.jetty.util.resource.PathResource;

Path pathA = Path.of(Sys.installForm);

PathResource resourceA = new PathResource(pathA);

System.out.println("pathA exists() = " + Files.exists(pathA));
System.out.println("pathA isDirectory() = " + Files.isDirectory(pathA));
System.out.println("resourceA = " + resourceA);
System.out.println("resourceA getURI() = " + resourceA.getURI());
System.out.println("resourceA realPath() = " + resourceA.getRealPath());
System.out.println("resourceA realURI() = " + resourceA.getRealURI());
System.out.println("resourceA isAlias() = " + resourceA.isAlias());
wise-coders commented 9 months ago

Here is the result:

pathA exists() = true
pathA isDirectory() = true
resourceA = file:///C:/work/dbschema/build/resources/main/forms/
resourceA getURI() = file:///C:/work/dbschema/build/resources/main/forms/
resourceA realPath() = C:\work\dbschema\build\resources\main\forms
resourceA realURI() = file:///C:/work/dbschema/build/resources/main/forms/
resourceA isAlias() = false

The code is slightly different, as the PathResource has no public constructor. So I used:

super( new InetSocketAddress("127.0.0.1", port));
        // ACCEPT ONLY CONNECTIONS FROM LOCALHOST
        try ( ServerConnector sc = new ServerConnector(this)) {
            sc.setPort(port);
            sc.setHost("localhost");
            setConnectors(new Connector[]{sc});

            this.contextHandler = new ServletContextHandler( "/", ServletContextHandler.SESSIONS );
            this.setHandler( contextHandler );

            Path pathA = new File(Sys.installForm).toPath();

            PathResource resourceA = (PathResource)ResourceFactory.of( this ).newResource( pathA );

            System.out.println("pathA exists() = " + Files.exists(pathA));
            System.out.println("pathA isDirectory() = " + Files.isDirectory(pathA));
            System.out.println("resourceA = " + resourceA);
            System.out.println("resourceA getURI() = " + resourceA.getURI());
            System.out.println("resourceA realPath() = " + resourceA.getRealPath());
            System.out.println("resourceA realURI() = " + resourceA.getRealURI());
            System.out.println("resourceA isAlias() = " + resourceA.isAlias());

            contextHandler.setBaseResource( resourceA );
            contextHandler.addServlet( new ServletHolder( new InternalImageServlet()), "/" + FormUtil.LOCAL_IMAGES + "*");
            contextHandler.addServlet( new ServletHolder( new DbImageServlet()), "/" + FormUtil.DATABASE_IMAGES + "*");

            // FILES ARE SERVED HERE
            ServletHolder holderDef = new ServletHolder( "default", DefaultServlet.class);
            holderDef.setInitParameter("dirAllowed", "false");
            contextHandler.addServlet(holderDef, "/");
        }
joakime commented 9 months ago

Thanks, I have enough to attempt to replicate, please be patient (new years and all)