Using Freemarker with Restlet 2.0 in a Java EE server - servlets

I'm a bit confused with what is written in the documentation(s) for Freemarker and Restlet's freemarker extension.
Here's the situation: The restlet engine serves an HTML representation of a resource (e.g. www.mysite.com/{user}/updates). The resource returned for this URI is an HTML page containing all the updates, that is created with a freemarker template. This application is hosted on a Glassfish v3 server
Question(s):
The freemarker configuration should only be loaded once as per the freemarker documentation:
/* You should do this ONLY ONCE in the whole application life-cycle:Create and adjust the configuration */
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(
new File("/where/you/store/templates"));
cfg.setObjectWrapper(new DefaultObjectWrapper());
What is the best place to do this in a Java EE app? I am thinking of having it as context-param in web.xml and using a ServletContextListener - but I'm not sure how to go about doing that.
As per freemarker's documentation we could also add a freemarkerservlet and map .ftl url-patterns to it. But this is already mapped by a Restlet servlet (i.e., the url-pattern of "/"). So having another one for *.ftl doesn't make sense (or does it?)
So the question is basically about how best to integrate with the 'configuration' of Freemarker so that it happens only once and what is the 'entry-point' for that piece of code (who calls it). Has anyone successfully used Freemarker + restlet in a Java EE environment? Any ideas?
Thanks!

This was a tricky question - indeed. Required me to go through the implementation of the source files in org.restlet.ext.Freemarker package - Phew!
Here's how you can do it
If you need to create your OWN Configuration Object, set the 'templateLoader' to use and then have TemplateRepresentation 'work' on it for rendering:
Configuration cfg = new Configuration();
ContextTemplateLoader loader = new ContextTemplateLoader(getContext(),"war:///WEB-INF");
cfg.setTemplateLoader(loader);
TemplateRepresentation rep = null;
Mail mail = new Mail(); //The data object you wish to populate - example from Restlet itself
mail.setStatus("received");
mail.setSubject("Message to self");
mail.setContent("Doh!");
mail.setAccountRef(new Reference(getReference(), "..").getTargetRef()
.toString());
Map<String, Object> data = new HashMap<String, Object>();
data.put("status", mail.getStatus());
data.put("subject", mail.getSubject());
data.put("content", mail.getContent());
data.put("accountRef", mail.getAccountRef());
rep = new TemplateRepresentation("Mail.ftl", cfg, data, MediaType.TEXT_HTML);
return rep;
If you are happy with the default and wish to use a class loader based way of loading the templates
//Load the FreeMarker template
Representation mailFtl = new ClientResource(
LocalReference.createClapReference(getClass().getPackage())
+ "/Mail.ftl").get();
//Wraps the bean with a FreeMarker representation
return new TemplateRepresentation(mailFtl, mail, MediaType.TEXT_HTML);
If you want to initialize the Configuration Object once and set the template by calling the setServletContextForTemplateLoading(...) method on the configuration object. You could always do this in a ServletContextListener
public class Config implements ServletContextListener {
private static Configuration cfg = new Configuration();
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
cfg.setServletContextForTemplateLoading(sc, "/WEB-INF");
}
public static Configuration getFMConfig()
{
return cfg;
}
}
And then call the static getFMConfig() and pass it to TemplateRepresentation as in 1
Things to note:
If you do get a protocol not supported Exception it'll be in case 2. Implies that the ServerResource doesn't know what protocol to use to access the file - It'll be the CLAP protocol of Restlet. You may have to set up the init-params for RestletServlet in the web.xml file and have CLAP as one of the param-values
The TemplateRepresentation has quite a few constructors - if you DON'T pass in a configuration object during instantiation (using another overloaded constructor), it will create a new Configuration() for you. So you don't have to do any configuration set up as in 2 (This may strike you as obvious but I assumed that you WOULD still need to set a configuration or it would 'pick it up from somewhere')
If you DO wish to have your OWN configuration setup you MUST pass it to one of the constructors
Have a look at the "war:///" string in the constructor of ContextTemplateLoader in 1. this is important No where is it mentioned what this baseUri reference should be, not even in the docs. I tried for quite a while before figuring it out that it should be "war:///" followed by the folder name where the templates are stored.
For case 2 you'll probably have to store the templates in the same package as the class file from where this code is accessed. If you see carefully you'll notice a LocalReference parameter as an argument to ClientResource saying that the resource is supposed to be locally present and thus you need to use the custom CLAP protocol (classLoader Access Protocol)
Personal Frustration point - why isn't all this even clarified in the documentation or ANYWHERE :)
Hope it helps someone who stumbles upon this post! Phew!

Related

Service Fabric Web API Versioning issue

I'm working on a service fabric project with multiple stateless services. When i try to add versioning as in the code below
[Authorize]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class SessionController : Controller
{
...
}
it's not working when calling the service later using Postman or using some client winforms app i made just to call this service. And when i say it's not working i mean it's not looking for a specific version i placed in the controller.
e.g.
I'm calling http://localhost:1234/api/v1.0/session/set-session and as you can see in my controller i only have version 2.0. Now my API gets hit this way or another no matter what version number i put in.
I added code to the Startup.cs
services.AddApiVersioning(options => {
options.DefaultApiVersion = new ApiVersion(2, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = new HeaderApiVersionReader("x-api-version");
});
Specific API call looks like this:
[HttpPost]
[Route("set-session")]
public async Task<IActionResult> SetSession([FromBody] SessionModel model)
{ ... }
Can anyone tell me what am i missing or maybe api versioning is not supported in service fabric at all?
Thanks.
Does your solution work locally? Based on what I see, I would suspect - no. This should have nothing to do with Service Fabric at all.
Issue 1
I see that your base class inherits from Controller, which is allowed, but is usually ControllerBase. No concern there, just FYI. The crux of the problem is likely that your controller has not applied the [ApiController] attribute. API Versioning defines IApiControllerSpecification and IApiControllerFilter, which is used to filter which controllers should be considered an API. This is important for developers building applications that have the UI and API parts mixed. A controller is a controller in ASP.NET Core and it was difficult to distinguish these two in the early days. There is now a built-in IApiControllerSpecification that considers any controller with [ApiController] applied to be an API. This can be changed, replaced, or completely disabled using ApiVersioningOptions.UseApiBehavior = false.
If your library/application is only APIs, you can decorate all controllers at once using:
[assembly: ApiController]
Since your controller is not currently being considered an API, all requests matching the route are being directed there. The value 1.0 is being considered an arbitrary string rather than an API version. This is why it matches at all instead of HTTP 400. I suspect you must only have one API and it is defined as 2.0; otherwise, I would expect an AmbiguousActionException.
Issue 2
Your example shows that you are trying to version by URL segment, but you've configured the options to only consider the header x-api-version. This option should be configured with one of the following:
URL Segment (only)
options.ApiVersionReader = new UrlSegmentApiVersionReader();
URL Segment and Header
// registration order is irrelevant
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("x-api-version"));
Default (Query String and URL Segment)
// NOTE: this is the configuration
// options.ApiVersionReader = ApiVersionReader.Combine(
// new QueryStringApiVersionReader(),
// new UrlSegmentApiVersionReader());
Side Note
As defined, using the URL segment and header versioning methodologies don't make sense. You have a single route which requires an API version. A client will always have to include the API version in every request so there is no point to also supporting a header.
If you define 2 routes, then it makes sense:
[Route("api/[controller]")] // match by header
[Route("api/v{version:apiVersion}/[controller]")] // match by url segment
Versioning by URL segment, while common, is the least RESTful. It violates the Uniform Interface constraint. This issue demonstrates yet another problem with that approach. Query string, header, media type, or any combination thereof will all work with the single route template of: [Route("api/[controller]")]
Observation 1
You have configured options.AssumeDefaultVersionWhenUnspecified = true. This will have no effect when versioning by URL segment. It is impossible to provide a default value of route parameter in the middle of a template. The same would be true for api/value/{id}/subvalues if {id} is not specified.
This option will have an effect if you:
Add a second route template that doesn't have the API version parameter
You update your versioning strategy to not use a URL segment
It should be noted that is a highly abused feature. It is meant to grandfather in existing services that didn't previously have explicit versioning because adding it will break existing clients. You should be cognizant of that if that isn't your use case.

Injecting into constructor with 2 params is not working

I have a ASP .Net Web API controller that I want to take 2 parameters. The first one is an EF context and the second being a caching interface. If I just have the EF context the constructor gets called, but when I add the caching interface I get the error:
An error occurred when trying to create a controller of type
'MyV1Controller'. Make sure that the controller has a
parameterless public constructor.
private MyEntities dbContext;
private IAppCache cache;
public MyV1Controller(MyEntities ctx, IAppCache _cache)
{
dbContext = ctx;
cache = _cache;
}
My UnityConfig.cs
public static void RegisterTypes(IUnityContainer container)
{
// TODO: Register your types here
container.RegisterType<MyEntities, MyEntities>();
container.RegisterType<IAppCache, CachingService>();
}
I would expect that Entity now knows about both types when a request is made for MyV1Controller function it should be able to instantiate an instance since that constructor takes types it knows about but that's not the case. Any idea why?
[EDIT]
Note that I created my own class (IConfig) and registered it and add it to the constructor and it worked, but whenever I try to add the IAppCache to my constructor and make a request to the API I get the error telling me it can't construct my controller class. The only difference that I see is the IAppCache isn't in my projects namespace because it's a 3rd party class but that shouldn't matter from what I understand.
Here are the constructors for CachingService
public CachingService() : this(MemoryCache.Default) { }
public CachingService(ObjectCache cache) {
if (cache == null) throw new ArgumentNullException(nameof(cache));
ObjectCache = cache;
DefaultCacheDuration = 60*20;
}
Check the IAppCacheimplementation CachingService to make sure that the class is not throwing any exception when initialized. that parameterless exception is the default message when an error occurs while trying to create controllers. It is not a very useful exception as it does not accurately indicate what the true error was that occurred.
You mention that it is a 3rd party interface/class. It could be requesting a dependency that the container does not know about.
Referencing Unity Framework IoC with default constructor
Unity is calling the constructor with the most parameters which in this case is...
public CachingService(ObjectCache cache) { ... }
As the container know nothing about ObjectCache it will pass in null which according to the code in the constructor will throw an exception.
UPDATE:
Adding this from comments as it can prove useful to others.
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default));
Reference here Register Constructors and Parameters for more details.
Most of the DI containers while trying to resolve a type always look for a constructor with maximum number of parameters. That is the reason why CachingService(ObjectCache cache) constructor was being invoked by default. As ObjectCache instance is not registered with Unity, so the resolution fails. Once you force the type registration to invoke specific constructor, everything works.
So if you register IAppCache and force it to invoke CachingService() - parameter less constructor, it will work as expected.
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor());
Registering it this way, will force the parameter less constructor to be invoked and internally it will fall back on whatever the third part library wants to use as default. In your case it will be
CachingService() : this(MemoryCache.Default)
Another option that was mentioned in other answers is to register and pass the constructor parameter your self.
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default));
This will also work, but here you are taking the responsibility of supplying the cache provider. In my opinion, I would rather let the third party library handle its own defaults instead of me as a consumer taking over that responsibility.
Please take a look at How does Unity.Resolve know which constructor to use?
And few additional information for Niject
https://github.com/ninject/ninject/wiki/Injection-Patterns
If no constructors have an [Inject] attribute, Ninject will select the
one with the most parameters that Ninject understands how to resolve.
For LazyCache version 2.1.2 (maybe even earlier) the existing solution no longer works (no constructor that receives MemoryCache), but it works as simple as:
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor());
This worked with .NET Framework 4.6.1, Unity Abstractions 3.1.0.

Where to hook up authentication in Grizzly?

I'm using a Grizzly HttpServer which has two HttpHandler instances registered:
under /api/* there is an Jersey REST - style application offering the API of the product, and
under /* there is an StaticHttpHandler which serves static HTML / JavaScript content (which, among other things, talks to the API under /api/
For authentication I'm currently securing only the API using a Jersey ContainerRequestFilter implementing HTTP Basic Auth, which looks quite similar to what is presented in another SO question.
But as requirements changed, now I'd like to require authentication for all requests hitting the server. So I'd like to move the authentication one level up, from Jersey to Grizzly. Unfortunately, I'm completely lost figuring out where I can hook up a "request filter" (or whatever it is called) in Grizzly. Can someone point me to the relevant API to accomplish this?
The easiest solution would leverage the Grizzly embedded Servlet support.
This of course would mean you'd need to do a little work to migrate your current HttpHandler logic over to Servlets - but that really shouldn't be too difficult as the HttpHandler API is very similar.
I'll give some high level points on doing this.
HttpServer server = HttpServlet.createSimpleServer(<docroot>, <host>, <port>);
// use "" for <context path> if you want the context path to be /
WebappContext ctx = new WebappContext(<logical name>, <context path>);
// do some Jersey initialization here
// Register the Servlets that were converted from HttpHandlers
ServletRegistration s1 = ctx.addServlet(<servlet name>, <Servlet instance or class name>);
s1.addMapping(<url pattern for s1>);
// Repeat for other Servlets ...
// Now for the authentication Filter ...
FilterRegistration reg = ctx.addFilter(<filter name>, <filter instance or class name>);
// Apply this filter to all requests
reg.addMapping(null, "/*");
// do any other additional initialization work ...
// "Deploy" ctx to the server.
ctx.deploy(server);
// start the server and test ...
NOTE: The dynamic registration of Servlets and Filters is based off the Servlet 3.0 API, so if you want information on how to deal with Servlet listeners, init parameters, etc., I would recommend reviewing the Servlet 3.0 javadocs.
NOTE2: The Grizzly Servlet implementation is not 100% compatible with the Servlet specification. It doesn't support standard Servlet annotations, or deployment of traditional Servlet web application archive deployment.
Lastly, there are examples of using the embedded Servlet API here
The "hookup" part can be done using a HttpServerProbe (tested with Grizzly 2.3.5):
srv.getServerConfiguration().getMonitoringConfig().getWebServerConfig()
.addProbes(new HttpServerProbe.Adapter() {
#Override
public void onRequestReceiveEvent(HttpServerFilter filter,
Connection connection, Request request) {
...
}
#Override
public void onRequestCompleteEvent(HttpServerFilter filter,
Connection connection, Response response) {
}
});
For the "linking" to the ContainerRequestFilter you might want to have a look at my question:
UnsupportedOperationException getUserPrincipal

Write Junit tests for Spring MVC application which internally relies upon ContextLoader.getCurrentWebApplicationContext()

I'm trying to write integration tests for a controller in our spring mvc application. The controller invokes a service class which in turn invokes a dao to read/write data from the repository. The DAO needs to lookup some configuration. The configuration bean is defined in WEB-INF/applicationContext.xml.
I'm using something like this:
Configuration config =(Configuration)ContextLoader.getCurrentWebApplicationContext().getBean("config");
private String namespace = config.getProperty("someproperty");
The properties are stored in zookeeper so I'm not using spring's property management artifacts.
The problem is that while running the JUnit test ContextLoader.getCurrentWebApplicationContext() always returns null.
I have so far looked at the following approaches:
1. Ted Young's approach ( just google search for spring mvc integration tests ted young)
2. https://github.com/SpringSource/spring-test-mvc
3. this site.. questions/8464919/unit-testing-a-servlet-that-depends-on-springs-webapplicationcontextutils-getre
4. Use Selenium/JWebunit
5. http://confluence.highsource.org/display/Hifaces20/Hifaces20+Testing+package+-+testing%2C+tracing+and+debugging+web+applications+with+Jetty
1 doesn't resolve this issue. WebApplicationContext stays null
2 states that support for WebApplicationContext will be available in spring 3.2
3. I don't understand this. Where do I get the testApplicationContext and the getServletContext() from?
4. I do not want to go this way as this is completely blackbox testing.
5. I'm currently looking at 5. But this requires starting up a servlet container. Is there no other alternative?
I will appreciate any help you can provide.
Thanks
PixalSoft
#Ted Young SO didn't allow me to finish what I was saying.With loader=MockWebApplicationContextLoader,isn't it supposed to be available as the default contextloader exactly as the Spring ContextLoader behaves when the webapp is initialized by a servletcontainer?Is there something special I need to do get a handle on the MockWebApplicationContextLoader?Injecting the config object works for singleton objects. But all can't be singleton. Passing a config object in every constructor sounds too tedious. For now, I have created a class which has a static config object, autowired via a setter method. I will take a look at ApplicationContextAware.Many thx
You have to manually add the WebApplication context to ContextLoderListner.
This will work.
#ContextConfiguration(locations = "classpath:module-test-beans.xml")
#WebAppConfiguration
public class SampleTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext wac;
#BeforeClass
public void setUp() throws ServletException {
MockServletContext sc = new MockServletContext("");
ServletContextListener listener = new ContextLoaderListener(wac);
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
}
#Test
public void testMe() {
Assert.assertFalse(ContextLoader.getCurrentWebApplicationContext() == null);
}
}
Add the following code at the beginning of your junit test:
MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml"); // <== Customize with your paths
ServletContextListener listener = new ContextLoaderListener();
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
If you need to add more than one xml for the context path just put them in the same string separated with spaces, like this:
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml /applicationContext-other.xml");
The reason why ContextLoader.getCurrentWebApplicationContext is returning null is because, when you use my MockWebApplicationContextLoader, you are neither using a web application context nor that particular ContextLoader implementation.
Since your repository is managed by Spring, why do not you simply inject the config object into the repository? Injecting the config object is the most appropriate way to get access to it. You can then initialize your namespace property in a method annotated with #PostConstruct.
Alternatively, your DOA could implement ApplicationContextAware to receive a copy of the application context during construction.
store your property file in your classpath.
now access that property in your controller class like this:
/*to access your filename.properties file */
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
String sServerLocation = properties.getProperty("key");
now you can access your property file.
I am sure it will work.

File not found in EAR packaging

Inside my .ear
-META-INF
-lib
-ejb-shared.jar
-ejb.jar
-com/ejb/... (classes)
-fileXml.xml (file I'm trying to access)
-web.war
Some description:
"ejbshared" contains some ejbs and JPA entities
"ejb" contains some ejbs and JPA entities and uses "ejb-shared" project
The problem is that I can't access fileXml.xml. Inside an EJB bean (of ejb.jar) I've done:
File f = new File("fileXml.xml");
System.out.println(f.exists()); // returns false!
I don't know why, but it seems that fileXml.xml is not in the classpath, althougth it's present in the .ear, or maybe I'm doing things in the wrong way!
Using new File("fileXml.xml") will reference a file in the current working directory of the application server JVM, not relative to your specific application. Try using:
URL url = getClass().getResource("/fileXml.xml");
boolean exists = url != null;
System.out.println(exists);
InputStream input = url.openStream();
// ... read and close input stream

Resources