How to prevent caching of static files in embedded Jetty instance? - caching

I want to prevent my CSSs from being cached on the browser side. How can I do it in embedded Jetty instance?
If I were using xml configuration file, I would add lines like:
<init-param>
<param-name>cacheControl</param-name>
<param-value>max-age=0,public</param-value>
</init-param>
How I can turn that into the code?
Right now I start Jetty this way:
BasicConfigurator.configure();
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
// 1 hour
connector.setMaxIdleTime( 1000 * 60 * 60 );
connector.setSoLingerTime( -1 );
connector.setPort( 8081 );
server.setConnectors( new Connector[] { connector } );
WebAppContext bb = new WebAppContext();
bb.setServer( server );
bb.setContextPath( "/" );
bb.setWar( "src/webapp" );
server.addHandler( bb );
I think I should search setControlCache somewhere in the WebAppContext area of responsibility.
Any advices on this?

I normally use a ServletHolder, like this:
WebAppContext context = new WebAppContext();
ServletHolder servletHolder = new ServletHolder(MyServlet.class);
servletHolder.setInitParameter("cacheControl","max-age=0,public");
context.addServlet(servletHolder, "myservletpath");
While this does not exactly match your code you should be able to figure it out from there ?

Duh, how to do just the opposite How to configure cache for static resources in web.xml for Jetty??

And here's just a working code with no need to figure out, guess and try. It's provided with respect to code in question and jetty 6. For jetty 7 and higher need to change Context to ServletContextHandler.
BasicConfigurator.configure();
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
// 1 hour
connector.setMaxIdleTime( 1000 * 60 * 60 );
connector.setSoLingerTime( -1 );
connector.setPort( 8081 );
server.setConnectors( new Connector[] { connector } );
//--- The difference with code in question starts here
DefaultServlet defaultServlet = new DefaultServlet();
ServletHolder holder = new ServletHolder(defaultServlet);
holder.setInitParameter("useFileMappedBuffer", "false");
holder.setInitParameter("cacheControl", "max-age=0, public");
Context bb = new Context();
bb.setResourceBase("src/webapp");
bb.addServlet(holder, "/");
//--- Done. Caching is off!
server.addHandler( bb );
// Run server as usual with server.run();
My sample also sets useFileMappedBuffer to false which is needed for not blocking files on a disk if you are developing on Windows by any reason.

I use resourceHandler for static contents.
Here's a code working fine on Jetty 9.
ResourceHandler rh = new ResourceHandler();
rh.setResourceBase([your_resource_base_dir]);
rh.setCacheControl("no-store,no-cache,must-revalidate");

Related

Using spring-session-hazelcast on Kubernetes with service-dns causing SplitBrainMergeValidationOp ERROR

We are deploying a spring-boot application using spring-session-hazelcast + hazelcast-kubernetes on an OpenShift/Kubernetes cluster.
Due to the nature of our platform, we can only use service-dns configuration. We expose a service on port 5701 for multicasting and set service-dns property to the multicast service name.
Below is a snippet for creation of the Hazelcast instance.
#Bean
public HazelcastInstance hazelcastInstance() {
var config = new Config();
config.setClusterName("spring-session-cluster");
var join = config.getNetworkConfig().getJoin();
join.getTcpIpConfig().setEnabled(false);
join.getMulticastConfig().setEnabled(false);
join.getKubernetesConfig().setEnabled(true)
.setProperty("service-dns", "<multicast-service-name>");
var attribute = new AttributeConfig()
.setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
.setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName());
config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
.addAttributeConfig(attribute)
.addIndexConfig(new IndexConfig(IndexType.HASH, Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
var serializer = new SerializerConfig();
serializer.setImplementation(new HazelcastSessionSerializer())
.setTypeClass(MapSession.class);
config.getSerializationConfig().addSerializerConfig(serializer);
return Hazelcast.newHazelcastInstance(config);
}
When we run 2 pods for this application, we see the below ERROR log:
com.hazelcast.internal.cluster.impl.operations.SplitBrainMergeValidationOp
Message: [<private-ip>]:5701 [spring-session-cluster] [4.2] Target is this node! -> [<private-ip>]:5701
Can someone please explain how to fix this error, still using "service-dns" configuration?
You need to enable headless mode for your service in openshift.
https://github.com/hazelcast/hazelcast-kubernetes#dns-lookup
Just add configuration for split brain protection
SplitBrainProtectionConfig splitBrainProtectionConfig = new SplitBrainProtectionConfig();
splitBrainProtectionConfig.setName("splitBrainProtectionRuleWithFourMembers")
.setEnabled(true)
.setMinimumClusterSize(4);
MapConfig mapConfig = new MapConfig();
mapConfig.setSplitBrainProtectionName("splitBrainProtectionRuleWithFourMembers");
Config config = new Config();
config.addSplitBrainProtectionConfig(splitBrainProtectionConfig);
config.addMapConfig(mapConfig);
You can read more about this in hazelcast documentation:
https://docs.hazelcast.com/imdg/4.2/network-partitioning/split-brain-protection.html

Jetty RewriteHandler and contextHandler

I have an application running on an embeded jetty server. I'm trying to add a write to add a RewriteHandler in order to redirect from the root of my web-application (http:///www.example.com) to (http:www.example.com/web).
I added the RewriteHandler, however I'm being redirected to http://www.example.com/home.html (or main.html, depending on if the user has signed in or not).
I actually want to be redirected to http://www.example.com/web/home.html.
How should I modify the code below, in order for that to happen:
ServletContextHandler servletHandler =
new ServletContextHandler(ServletContextHandler.SESSIONS);
ServletHolder jerseyServlet = servletHandler.addServlet(ServletContainer.class, "/*");
String staticPath = StartServer.class.getResource("/resources/www-static/").toExternalForm();
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setBaseResource(Resource.newResource(staticPath));
resourceHandler.setWelcomeFiles(new String[] { "home.html" });
ContextHandler staticHandler = new ContextHandler("/web");
staticHandler.setHandler(resourceHandler);
RewriteHandler rewriteHandler = new RewriteHandler();
rewriteHandler.setRewriteRequestURI(true);
rewriteHandler.setRewritePathInfo(false);
RewritePatternRule redirect = new RewritePatternRule();
redirect.setPattern("^/?$");
redirect.setReplacement("/web");
rewriteHandler.addRule(redirect);
rewriteHandler.setHandler(resourceHandler);
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { servletHandler, staticHandler, rewriteHandler });
jetty.setHandler(handlers);
Put RewriteHandler first.
And don't mix ServletContextHandler and ResourceHandler.
See https://stackoverflow.com/a/28419106/775715 and https://stackoverflow.com/a/34277268/775715

Trying to set up Orleans Cluster membership with Consul

I'm trying to use an existing Consul cluster as the membership provider for a test Orleans application.
I get this error when connecting my client app to the Silo
Could not find any gateway in Orleans.Runtime.Host.ConsulBasedMembershipTable. Orleans client cannot initialize.
Digging into the ConsulUtils class, the entries being retrieved have no ProxyPort defined - and are discarded - hence the empty result set.
I initialize the silo like this:
var clusterConfiguration = new ClusterConfiguration();
clusterConfiguration.Globals.DataConnectionString = "http://localhost:8500";
clusterConfiguration.Globals.DeploymentId = "OrleansPlayground";
clusterConfiguration.Globals.LivenessType = GlobalConfiguration.LivenessProviderType.Custom;
clusterConfiguration.Globals.MembershipTableAssembly = "OrleansConsulUtils";
clusterConfiguration.Globals.ReminderServiceType = GlobalConfiguration.ReminderServiceProviderType.Disabled;
var silohost = new SiloHost("Fred", clusterConfiguration);
silohost.InitializeOrleansSilo();
startup = Task.Factory.StartNew(() =>
{
return silohost.StartOrleansSilo();
});
return true;
And I set my client app up like this:
var config = new ClientConfiguration();
config.CustomGatewayProviderAssemblyName = "OrleansConsulUtils";
config.DataConnectionString = "http://localhost:8500";
config.DeploymentId = "OrleansPlayground";
config.GatewayProvider = ClientConfiguration.GatewayProviderType.Custom;
GrainClient.Initialize(config);
Looking at the code in ConsulUtils I can see that the ProxyPort isn't set (i.e. is 0) when the entry is saved. So I'm assuming I have a problem when initializing the silo - but I can't figure out what it is!
Without digging deep in, does sound like a bug. Please repost on GitHub and we will try to help you.

With Drools 6.x how do I avoid Maven and the Compiler?

I'm looking into providing a 'hot-swap' capability for switching between different versions of sets of drools rules. The target deployment is in WebSphere, and the rules will all be run in stateless session beans. Ideally I want to pre-compile and package the rules into some discrete file and get the Application Server to determine that new rules are available, and load them (skipping the compilation step).
The Drools documentation indicates this should be possible - but is splendidly vague on the mechanics. The details on the Java EE side are not an issue but the pre-compilation is providing an headache.
Following some posts I've pulled together some logic which I thought would do the trick - the following compiles a rules file and serializes it out to disk:
private void process(String outputFile, String inputFile) throws Exception {
String drl = fileToString(inputFile);
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", drl );
ks.newKieBuilder( kfs ).buildAll();
ReleaseId releaseId = ks.getRepository().getDefaultReleaseId();
InternalKieModule kieModule = (InternalKieModule) ks.getRepository().getKieModule( releaseId );
byte[] jar = kieModule.getBytes();
serialize(jar, outputFile);
System.out.println("Class of InternalKieModule is " + kieModule.getClass());
}
The following reads it back ready to create a KieSession:
private KieContainer getKbase(KieServices ks) throws Exception {
byte[] jar = deserialize(RULES_SER);
Resource jarRes = ks.getResources().newByteArrayResource(jar);
KieModule km = ks.getRepository().addKieModule(jarRes);
releaseId = km.getReleaseId();
KieContainer kc = ks.newKieContainer(km.getReleaseId());
return kc;
}
Works fine BUT ... I was horrified to discover I seem to need everything but the kitchen sink to actually run it - just under 50 separate jar files - taking up 16 MB and including the Ant jar, 10 Maven jars, and the drools compiler jar even though I'm not supposed to be compiling anything, and I'm certainly not trying to use Maven or Ant! Of the 67 Jar files in the distribution nearly all seem directly linked to Maven, and very few (I'd judge from the approach below about 10 to 15) actually have anything to do with a rules runtime.
Going back to an example I built with Drools 5, several years back, I came up with the following code to reload a drl file I'd compiled separately using the Knowledge Base APIs:
private KnowledgeBase readSavedKnowledgeBase() throws Exception {
byte[] serializedKb = (byte[]) deserialize(RULES_SER);
ByteArrayInputStream bais = new ByteArrayInputStream(serializedKb);
DroolsObjectInputStream ois = new DroolsObjectInputStream(bais);
KnowledgeBase kbase = (KnowledgeBase) ois.readObject();
ois.close();
return kbase;
}
This works fine with 6.1. I only need 9 jars, (and I don't need the compiler jar) - and my run-time is a fairly reasonable 5MB. The down side is that Eclipse is unhappy since the KnowledgeBase class is now deprecated.
Could someone point the way to allowing me to get the same result using non-deprecated classes but without all the baggage of Maven and so on which I don't want or need to actually run some rules?
Some 6.x code for building:
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
FileInputStream fis = new FileInputStream( "sale/sale.drl" );
kfs.write( "src/main/resources/sale.drl",
ks.getResources().newInputStreamResource( fis ) );
KieBuilder kieBuilder = ks.newKieBuilder( kfs ).buildAll();
Results results = kieBuilder.getResults();
if( results.hasMessages( Message.Level.ERROR ) ){
System.out.println( results.getMessages() );
throw new IllegalStateException( "### errors ###" );
}
KieContainer kieContainer =
ks.newKieContainer( ks.getRepository().getDefaultReleaseId() );
// CEP - get the KIE related configuration container and set the EventProcessing (from default cloud) to Stream
KieBaseConfiguration config = ks.newKieBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
KieBase kieBase = kieContainer.newKieBase( config );
// KieSession kieSession = kieContainer.newKieSession();
KieSession kieSession = kieBase.newKieSession();
You can serialize out the KieBase and back in for fast startup. I run this for various tests using the below CLASSPATH, but for execution you'll not need antlr, decisiontables, templates, and (maybe) others.
export CLASSPATH=".:$root/drools-core-${tag}.jar:$root/kie-api-${tag}.jar:$roo/kie-internal-${tag}.jar:$root/knowledge-internal-api-${tag}.jar:$root/drools-compiler-${tag}.jar:$root/antlr-runtime-3.5.jar:$root/ecj-4.3.1.jar:$root/mvel2-2.1.9.Final.jar:$root/drools-decisiontables-${tag}.jar:$root/drools-templates-${tag}.jar:$root/protobuf-java-2.5.0.jar:$root/slf4j-api-1.7.2.jar:$root/xstream-1.4.7.jar:$SLF4J"
For serialiazation and its counterpart use the usual mantra:
ObjectOutputStream out =
new ObjectOutputStream( new FileOutputStream( pkgPath ) );
out.writeObject( kieBase );
out.close();
//---------- In another program ---------------
ObjectInputStream in =
new ObjectInputStream( new FileInputStream( pkgPath ) );
#SuppressWarnings( "unchecked" )
KieBase kieBase = (KieBase)in.readObject();
in.close();
It only brings in Maven if you have kie-ci on the classpath, remove that and you will not have any maven. However you will also not have any dependency management or pom analysis - if you don't need those things, you don't need maven to compile. Without kie-ci it will fall back to a "light" pom.xml parser. You can still programmatically provide it the other kiemodulies it depends on.

Adding different handler in single Jetty server

I need a jetty server with multiple servletHandler.
HTTPservlet:
ServletHandler servletHandler = new ServletHandler();
server.setHandler(servletHandler);
servletHandler.addServletWithMapping("com.realtime.webserver.MyServlet", "/MyServlet");
WebsocketServlet:
MyWebSocketHandler myWebSocketHandler = new MyWebSocketHandler ();
myWebSocketHandler.setHandler(new DefaultHandler());
server.setHandler(myWebSocketHandler);
server.start();
I need both should be in single server.
Is there any possibilities?
You can use org.eclipse.jetty.server.handler.HandlerCollection (Jetty 9)
HandlerCollection handlerCollection = new HandlerCollection();
handlerCollection.setHandlers(new Handler[] {servletHandler, myWebSocketHandler});
Later add handlers to the collection:
handlerCollection.addHandler(newHandler);
Finally,
server.setHandler(handlerCollection);
server.start();
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java
This is an example of using many handlers at once on the same server.
Eventually it will be added to the documentation here:
http://www.eclipse.org/jetty/documentation/current/embedded-examples.html
Until that time there are many other examples there that should help make things clearer as well.

Resources