Initially the
Servlet API specification states the following with respect to the
life cycle of Servlets:
The
servlet container calls the init method exactly once after
instantiating the servlet.
This
works perfectly in a regular servlet container which both
instantiates and initializes the servlets. With Sling the tasks of
instantiation and initialization are split:
The provider of the Servlet service takes care of creating the servlet instance
The Sling Servlet Resolver picks up the Servlet services and initializes and destroys them as needed
So
Sling has not way of making sure a Servlet is only initialized and
destroyed once in the life time of the Servlet object instance.
The
provider of the Servlet service on the other can cope with this
situation by making sure to drop the servlet instance once it is
destroyed. The mechanism helping the provider here is the OSGi
Service Factory.
Registering a Servlet :
Servlets
can be registered as OSGi services. The following service reference
properties are defined for Servlets defined as OSGi services of type
javax.servlet.Servlet:
- sling.servlet.paths
- sling.servlet.resourceTypes
- sling.servlet.selectors
- sling.servlet.extensions
- sling.servlet.methods
- sling.servlet.prefix
A
SlingServletResolver listens for Servlet{}services and - given the
correct service registration properties - provides the servlets as
resources in the (virtual) resource tree. Such servlets are provided
as ServletResource instances which adapt to the javax.servlet.Servlet
class.
For
a Servlet registered as an OSGi service to be used by the Sling
Servlet Resolver, either or both of the sling.servlet.paths or the
sling.servlet.resourceTypes service reference properties must be set.
If neither is set, the Servlet service is ignored.
Each
path to be used for registration - either from the
sling.servlet.paths property or constructed from the other
sling.servlet.\* properties - must be absolute. Any relative path is
made absolute by prefixing it with a root path. This prefix may be
set with the sling.servlet.prefix service registration property. If
this property is not set, the first entry in the ResourceResolver
search path for the ResourceResolver.getResource(String) method is
used as the prefix. If this entry cannot be derived, a simpe slash -
/ - is used as the prefix.
If
sling.servlet.methods is not specified, the servlet is only
registered for handling GET requests. Make sure to list all methods
you want to be handled by this servlet.
Registering a Servlet using Java Annotations
If
you are working with the default Apache Sling development stack you
can use Java Annotations from Apache Felix Maven SCR Plugin to
register your Sling servlets and describe their binding details.
sling.servlet.paths = \[ "/libs/sling/sample/html", "/libs/sling/sample/txt" \] sling.servlet.resourceTypes = \[ "sling/unused" \] sling.servlet.selectors = \[ "img" \] sling.servlet.extensions = \[ "html", "txt", "json" \]
These are the ways of doing , either with a Sling-specific
@SlingServlet annotation or with the more generic maven-scr-plugin
annotations etc..
1) The @SlingServlet annotation
@SlingServlet( resourceTypes = "sling/servlet/default", selectors = "hello", extensions = "html", methods = "GET") public class MyServlet extends SlingSafeMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { ... } }
2) The @Properties and @Property annotations
@Component(metatype = true) @Service(Servlet.class) @Properties({ @Property(name = "sling.servlet.resourceTypes", value = "sling/servlet/default"), @Property(name = "sling.servlet.selectors", value = "hello"), @Property(name = "sling.servlet.extensions", value = "html"), @Property(name = "sling.servlet.methods", value = "GET") }) public class MyServlet extends SlingSafeMethodsServlet { @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { ... } }
Upon
these we can define in following ways too
3) Registering the servlet by path
@SlingServlet
(
paths={
"/services/unicom/v1/"
}
)
@Properties
({
@Property
(name=
"service.pid"
,
value=
"com.adobe.unicom.v1.servlets.OmnnitureLoggingServlet"
,propertyPrivate=
false
),
@Property
(name=
"service.description"
,value=
"Omniture
service call logging servlet"
,
propertyPrivate=
false
),
@Property
(name=
"service.vendor"
,value=
"Adobe
Systems Incorporated - Adobe@Adobe Team"
,
propertyPrivate=
false
)
})
public
class
OmnnitureLoggingServlet
extends
SlingAllMethodsServlet
{
@Override
protected
void
doGet(SlingHttpServletRequest
request, SlingHttpServletResponse response)
throws
ServletException,
IOException
{
//Do
something fun here
}
@Override
protected
void
doPost(SlingHttpServletRequest
request, SlingHttpServletResponse response)
throws
ServletException,
IOException
{
//Do
something fun here
}
}
4) Registering the servlet by resource type and extension
@SlingServlet
(
resourceTypes
= {
"rep:User"
},
methods
= {
"GET"
,
"POST"
}
)
@Properties
({
@Property
(name=
"service.pid"
,
value=
"com.adobe.unicom.v1.servlets.OmnnitureLoggingServlet"
,propertyPrivate=
false
),
@Property
(name=
"service.description"
,value=
"Omniture
service call logging servlet"
,
propertyPrivate=
false
),
@Property
(name=
"service.vendor"
,value=
"Adobe
Systems Incorporated - Adobe@Adobe Team"
,
propertyPrivate=
false
)
})
public
class
OmnnitureLoggingServlet
extends
SlingAllMethodsServlet
{
@Override
protected
void
doGet(SlingHttpServletRequest
request, SlingHttpServletResponse response)
throws
ServletException,
IOException
{
//Do
something fun here
}
@Override
protected
void
doPost(SlingHttpServletRequest
request, SlingHttpServletResponse response)
throws
ServletException,
IOException
{
//Do
something fun here
}
}
5) handle all requests and filter on selector you can change the example above to read something like this.
@SlingServlet
(
resourceTypes
= {
"sling/servlet/default"
},
methods
= {
"GET"
},
selectors
= {
"report"
},
extensions
= {
"json"
}
)
@Properties
({
@Property
(name=
"service.pid"
,
value=
"com.adobe.unicom.v1.servlets.OmnnitureLoggingServlet"
,propertyPrivate=
false
),
@Property
(name=
"service.description"
,value=
"Omniture
service call logging servlet"
,
propertyPrivate=
false
),
@Property
(name=
"service.vendor"
,value=
"Adobe
Systems Incorporated - Adobe@Adobe Team"
,
propertyPrivate=
false
)
})
public
class
OmnnitureLoggingServlet
extends
SlingAllMethodsServlet
{
........
}
6) To handle all requests for a Page with a special selector.
ie
http://www.demosample.com/content/page.mycustomselector.html
@SlingServlet
(
resourceTypes
= {
"cq:Page"
},
methods
= {
"GET"
},
selectors
= {
"mycustomselector"
}
)
@Properties
({
@Property
(name=
"service.pid"
,
value=
"com.adobe.unicom.v1.servlets.OmnnitureLoggingServlet"
,propertyPrivate=
false
),
@Property
(name=
"service.description"
,value=
"Omniture
service call logging servlet"
,
propertyPrivate=
false
),
@Property
(name=
"service.vendor"
,value=
"Adobe
Systems Incorporated - Adobe@Adobe Team"
,
propertyPrivate=
false
)
})
public
class
OmnnitureLoggingServlet
extends
SlingAllMethodsServlet
{
........
}
7) To handle all requests for a Page with a special extension.
ie
http://www.demosample.com/content/page.mydemoext
@SlingServlet
(
resourceTypes
= {
"cq:Page"
},
methods
= {
"GET"
},
extensions
= {
"mydemoext"
}
)
@Properties
({
@Property
(name=
"service.pid"
,
value=
"com.adobe.unicom.v1.servlets.OmnnitureLoggingServlet"
,propertyPrivate=
false
),
@Property
(name=
"service.description"
,value=
"Omniture
service call logging servlet"
,
propertyPrivate=
false
),
@Property
(name=
"service.vendor"
,value=
"Adobe
Systems Incorporated - Adobe@Adobe Team"
,
propertyPrivate=
false
)
})
public
class
OmnnitureLoggingServlet
extends
SlingAllMethodsServlet
{
........
}
By
following these can define/achieve creation of servlets in cq5 as per our tech specs.
Here
we can prefer resourceType for writing SlingServlets most efficiently.
Some
of the reasons comes into picture while development phase itself.
There
are :
- While defining a path , you must be specific what all paths are allowed to be used in the ServletResource OSGi service. If you define something randomly, your servlet might not be fucntional. Only a limited paths are allowed and the rest are blocked unless you open them up. This is resolved using resourceType.
- You may have also configure the dispatcher , if you use some random path for your servlet. This might be a potential security threat and a needless configuration.
- You might also have to specify the paths to your consumers for your servlet and any change in that path could have a serious affect. This might not be the case when you use resourceType
References : http://hashimkhan.in/ , https://sling.apache.org/documentation/the-sling-engine/servlets.html , http://blogs.adobe.com/aaa/
Hope it helps :)
SonyCharan