blob: 302a0e3ef2ac3f6a4bda8c0e08dba17baa3353e3 [file] [log] [blame]
Vinay Vishal7c4c4fc2019-01-28 12:01:04 +05301type=page
2status=published
3title=Adding Container Capabilities
4next=session-persistence-modules.html
5prev=adding-configuration-data.html
6~~~~~~
7Adding Container Capabilities
8=============================
9
10[[GSACG00007]][[ghmon]]
11
12
13[[adding-container-capabilities]]
147 Adding Container Capabilities
15-------------------------------
16
Steve Millidge8ef0aa72020-10-25 16:36:38 +000017Applications run on Eclipse GlassFish Server in containers. GlassFish Server
Vinay Vishal7c4c4fc2019-01-28 12:01:04 +053018enables you to create containers that extend or replace the existing
19containers of GlassFish Server. Adding container capabilities enables
20you to run new types of applications and to deploy new archive types in
21GlassFish Server.
22
23The following topics are addressed here:
24
25* link:#ghpjl[Creating a `Container` Implementation]
26* link:#ghozu[Adding an Archive Type]
27* link:#ghphp[Creating Connector Modules]
28* link:#gkane[Example of Adding Container Capabilities]
29
30[[ghpjl]][[GSACG00132]][[creating-a-container-implementation]]
31
32Creating a `Container` Implementation
33~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34
35To implement a container that extends or replaces a service in GlassFish
36Server, you must create a Java programming language class that includes
37the following characteristics:
38
39* It is annotated with the `org.jvnet.hk2.annotations.Service`
40annotation.
41* It implements the `org.glassfish.api.container.Container` interface.
42
43You should also run the HK2 Inhabitants Generator utility on your class
44files, which adds classes marked with the `@Service` annotation to the
45`META-INF/hk2-locator/default` file in your JAR file. For more
46information about the HK2 Inhabitants Generator, see the
47https://hk2.java.net/inhabitant-generator.html[HK2 Inhabitants Generator
48page].
49
50[[ghogv]][[GSACG00234]][[marking-the-class-with-the-service-annotation]]
51
52Marking the Class With the `@Service` Annotation
53^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54
55Add a `com.jvnet.hk2.annotations.Service` annotation at the class
56definition level to identify your class as a service implementation.
57
58[source,oac_no_warn]
59----
60@Service
61public class MyContainer implements Container {
62...
63}
64----
65
66To avoid potential name collisions with other containers, use the fully
67qualified class name of your container class in the `@Service`
68annotation's `name` element:
69
70[source,oac_no_warn]
71----
72package com.example.containers;
73...
74
Steve Millidge8ef0aa72020-10-25 16:36:38 +000075@Service @jakarta.inject.Named("com.example.containers.MyContainer")
Vinay Vishal7c4c4fc2019-01-28 12:01:04 +053076public class MyContainer implements Container {
77...
78}
79----
80
81[[ghohg]][[GSACG00235]][[implementing-the-container-interface]]
82
83Implementing the `Container` Interface
84^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
85
86The `org.glassfish.api.container.Container` interface is the contract
87that defines a container implementation. Classes that implement
88`Container` can extend or replace the functionality in GlassFish Server
89by allowing applications to be deployed and run within the GlassFish
90Server runtime.
91
92The `Container` interface consists of two methods, `getDeployer` and
93`getName`. The `getDeployer` method returns an implementation class of
94the `org.glassfish.api.deployment.Deployer` interface capable of
95managing applications that run within this container. The `getName`
96method returns a human-readable name for the container, and is typically
97used to display messages belonging to the container.
98
99The `Deployer` interface defines the contract for managing a particular
100application that runs in the container. It consists of the following
101methods:
102
103`getMetaData`::
104 Retrieves the metadata used by the `Deployer` instance, and returns an
105 `org.glassfish.api.deployment.MetaData` object.
106`loadMetaData`::
107 Loads the metadata associated with an application.
108`prepare`::
109 Prepares the application to run in GlassFish Server.
110`load`::
111 Loads a previously prepared application to the container.
112`unload`::
113 Unloads or stops a previously loaded application.
114`clean`::
115 Removes any artifacts generated by an application during the `prepare`
116 phase.
117
118The `DeploymentContext` is the usual context object passed around
119deployer instances during deployment.
120
121[[GSACG00064]][[ghojg]]
122
123
124Example 7-1 Example Implementation of `Container`
125
126This example shows a Java programming language class that implements the
127`Container` interface and is capable of extending the functionality of
128GlassFish Server.
129
130[source,oac_no_warn]
131----
132package com.example.containers;
133contains
134@Service(name="com.example.containers.MyContainer")
135public class MyContainer implements Container {
136 public String getName() {
137 return "MyContainer";
138 }
139
140 public Class<? extends org.glassfish.api.deployment.Deployer> getDeployer() {
141 return MyDeployer.class;
142 }
143}
144----
145
146[[GSACG00065]][[ghoiv]]
147
148
149Example 7-2 Example Implementation of `Deployer`
150
151[source,oac_no_warn]
152----
153package com.example.containers;
154
155@Service
156public class MyDeployer {
157
158 public MetaData getMetaData() {
159 return new MetaData(...);
160 }
161
162 public <V> v loadMetaData(Class<V> type, DeploymentContext dc) {
163 ...
164 }
165
166 public boolean prepare(DeploymentContext dc) {
167 // performs any actions needed to allow the application to run,
168 // such as generating artifacts
169 ...
170 }
171
172 public MyApplication load(MyContainer container, DeploymentContext dc) {
173 // creates a new instance of an application
174 MyApplication myApp = new MyApplication (...);
175 ...
176 // returns the application instance
177 return myApp;
178 }
179
180 public void unload(MyApplication myApp, DeploymentContext dc) {
181 // stops and removes the application
182 ...
183 }
184
185 public void clean (DeploymentContext dc) {
186 // cleans up any artifacts generated during prepare()
187 ...
188 }
189}
190----
191
192[[ghozu]][[GSACG00133]][[adding-an-archive-type]]
193
194Adding an Archive Type
195~~~~~~~~~~~~~~~~~~~~~~
196
197An archive type is an abstraction of the archive file format. An archive
198type can be implemented as a plain JAR file, as a directory layout, or a
199custom type. By default, GlassFish Server recognizes JAR based and
200directory based archive types. A new container might require a new
201archive type.
202
203There are two sub-interfaces of the
204`org.glassfish.api.deployment.archive.Archive` interface,
205`org.glassfish.api.deployment.archive.ReadableArchive` and
206`org.glassfish.api.deployment.archive.WritableArchive`. Typically
207developers of new archive types will provide separate implementations of
208`ReadableArchive` and `WritableArchive`, or a single implementation that
209implements both `ReadableArchive` and `WritableArchive`.
210
211Implementations of the `ReadableArchive` interface provide read access
212to an archive type. `ReadableArchive` defines the following methods:
213
214`getEntry(String name)`::
215 Returns a `java.io.InputStream` for the specified entry name, or null
216 if the entry doesn't exist.
217`exists(String name)`::
218 Returns a `boolean` value indicating whether the specified entry name
219 exists.
220`getEntrySize(String name)`::
221 Returns the size of the specified entry as a `long` value.
222`open(URI uri)`::
223 Returns an archive for the given `java.net.URI`.
224`getSubArchive(String name)`::
225 Returns an instance of `ReadableArchive` for the specified sub-archive
226 contained within the parent archive, or null if no such archive
227 exists.
228`exists()`::
229 Returns a `boolean` value indicating whether this archive exists.
230`delete()`::
231 Deletes the archive, and returns a `boolean` value indicating whether
232 the archive has been successfully deleted.
233`renameTo(String name)`::
234 Renames the archive to the specified name, and returns a `boolean`
235 value indicating whether the archive has been successfully renamed.
236
237Implementations of the `WritableArchive` interface provide write access
238to the archive type. `WritableArchive` defines the following methods:
239
240`create(URI uri)`::
241 Creates a new archive with the given path, specified as a
242 `java.net.URI`.
243`closeEntry(WritableArchive subArchive)`::
244 Closes the specified sub-archive contained within the parent archive.
245`closeEntry()`::
246 Closes the current entry.
247`createSubArchive(String name)`::
248 Creates a new sub-archive in the parent archive with the specified
249 name, and returns it as a `WritableArchive` instance.
250`putNextEntry(String name)`::
251 Creates a new entry in the archive with the specified name, and
252 returns it as a `java.io.OutputStream`.
253
254[[ghoyp]][[GSACG00236]][[implementing-the-archivehandler-interface]]
255
256Implementing the `ArchiveHandler` Interface
257^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
258
259An archive handler is responsible for handling the particular layout of
Steve Millidge8ef0aa72020-10-25 16:36:38 +0000260an archive. Jakarta EE defines a set of archives (WAR, JAR, and RAR, for
Vinay Vishal7c4c4fc2019-01-28 12:01:04 +0530261example), and each of these archives has an `ArchiveHandler` instance
262associated with the archive type.
263
264Each layout should have one handler associated with it. There is no
265extension point support at this level; the archive handler's
266responsibility is to give access to the classes and resources packaged
267in the archive, and it should not contain any container-specific code.
268The `java.lang.ClassLoader` returned by the handler is used by all the
269containers in which the application will be deployed.
270
271`ArchiveHandler` defines the following methods:
272
273`getArchiveType()`::
274 Returns the name of the archive type as a `String`. Typically, this is
275 the archive extension, such as `jar` or `war`.
276`getDefaultApplicationName(ReadableArchive archive)`::
277 Returns the default name of the specified archive as a `String`.
278 Typically this default name is the name part of the `URI` location of
279 the archive.
280`handles(ReadableArchive archive)`::
281 Returns a `boolean` value indicating whether this implementation of
282 `ArchiveHandler` can work with the specified archive.
283`getClassLoader(DeploymentContext dc)`::
284 Returns a `java.lang.ClassLoader` capable of loading all classes from
285 the archive passed in by the `DeploymentContext` instance. Typically
286 the `ClassLoader` will load classes in the scratch directory area,
287 returned by `DeploymentContext.getScratchDir()`, as stubs and other
288 artifacts are generated in the scratch directory.
289`expand(ReadableArchive source, WritableArchive target)`::
290 Prepares the `ReadableArchive`source archive for loading into the
291 container in a format the container accepts. Such preparation could be
292 to expand a compressed archive, or possibly nothing at all if the
293 source archive format is already in a state that the container can
294 handle. This method returns the archive as an instance of
295 `WritableArchive`.
296
297[[ghphp]][[GSACG00134]][[creating-connector-modules]]
298
299Creating Connector Modules
300~~~~~~~~~~~~~~~~~~~~~~~~~~
301
302Connector modules are small add-on modules that consist of application
303"sniffers" that associate application types with containers that can run
304the application type. GlassFish Server connector modules are separate
305from the associated add-on module that delivers the container
306implementation to allow GlassFish Server to dynamically install and
307configure containers on demand.
308
309When a deployment request is received by the GlassFish Server runtime:
310
3111. The current `Sniffer` implementations are used to determine the
312application type.
3132. Once an application type is found, the runtime looks for a running
314container associated with that application type. If no running container
315is found, the runtime attempts to install and configure the container
316associated with the application type as defined by the `Sniffer`
317implementation.
3183. The `Deployer` interface is used to prepare and load the
319implementation.
320
321[[ghozd]][[GSACG00237]][[associating-file-types-with-containers-by-using-the-sniffer-interface]]
322
323Associating File Types With Containers by Using the `Sniffer` Interface
324^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
325
326Containers do not necessarily need to be installed on the local machine
327for GlassFish Server to recognize the container's application type.
328GlassFish Server uses a "sniffer" concept to study the artifacts in a
329deployment request and to choose the associated container that handles
330the application type that the user is trying to deploy. To create this
331association, create a Java programming language class that implements
332the `org.glassfish.api.container.Sniffer` interface. This implementation
333can be as simple as looking for a specific file in the application's
334archive (such as the presence of `WEB-INF/web.xml`), or as complicated
335as running an annotation scanner to determine an XML-less archive (such
336as enterprise bean annotations in a JAR file). A `Sniffer`
337implementation must be as small as possible and must not load any of the
338container's runtime classes.
339
340A simple version of a `Sniffer` implementation uses the `handles` method
341to check the existence of a file in the archive that denotes the
342application type (as `WEB-INF/web.xml` denotes a web application). Once
343a `Sniffer` implementation has detected that it can handle the
344deployment request artifact, GlassFish Server calls the `setUp` method.
345The `setUp` method is responsible for setting up the container, which
346can involve one or more of the following actions:
347
348* Downloading the container's runtime (the first time that a container
349is used)
350* Installing the container's runtime (the first time that a container is
351used)
352* Setting up one or more repositories to access the runtime's classes
353(these are implementations of the HK2
354`com.sun.enterprise.module.Repository` interface, such as the
355`com.sun.enterprise.module.impl.DirectoryBasedRepository` class)
356
357The `setUp` method returns an array of the
358`com.sun.enterprise.module.Module` objects required by the container.
359
360The `Sniffer` interface defines the following methods:
361
362`handles(ReadableArchive source, ClassLoader loader)`::
363 Returns a `boolean` value indicating whether this `Sniffer`
364 implementation can handle the specified archive.
365`getURLPatterns()`::
366 Returns a `String` array containing all URL patterns to apply against
367 the request URL. If a pattern matches, the service method of the
368 associated container is invoked.
369`getAnnotationTypes()`::
370 Returns a list of annotation types recognized by this `Sniffer`
371 implementation. If an application archive contains one of the returned
372 annotation types, the deployment process invokes the container's
373 deployers as if the `handles` method had returned true.
374`getModuleType()`::
375 Returns the module type associated with this `Sniffer` implementation
376 as a `String`.
377`setup(String containerHome, Logger logger)`::
378 Sets up the container libraries so that any dependent bundles from the
379 connector JAR file will be made available to the HK2 runtime. The
380 `setup` method returns an array of `com.sun.enterprise.module.Module`
381 classes, which are definitions of container implementations. GlassFish
382 Server can then load these modules so that it can create an instance
383 of the container's `Deployer` or `Container` implementations when it
384 needs to. The module is locked as long as at least one module is
385 loaded in the associated container.
386`teardown()`::
387 Removes a container and all associated modules in the HK2 modules
388 subsystem.
389`getContainerNames()`::
390 Returns a `String` array containing the `Container` implementations
391 that this `Sniffer` implementation enables.
392`isUserVisible()`::
393 Returns a `boolean` value indicating whether this `Sniffer`
394 implementation should be visible to end-users.
395`getDeploymentConfigurations(final ReadableArchive source)`::
396 Returns a `Map<String, String>` of deployment configuration names to
397 configurations from this `Sniffer` implementation for the specified
398 application (the archive source). The names are created by GlassFish
399 Server; the configurations are the names of the files that contain
400 configuration information (for example, `WEB-INF/web.xml` and possibly
401 `WEB-INF/sun-web.xml` for a web application). If the
402 `getDeploymentConfigurations` method encounters errors while searching
403 or reading the specified archive source, it throws a
404 `java.io.IOException`.
405
406[[ghpbx]][[GSACG00172]][[making-sniffer-implementations-available-to-the-glassfish-server]]
407
408Making `Sniffer` Implementations Available to the GlassFish Server
409++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
410
411Package `Sniffer` implementation code into modules and install the
412modules in the as-install`/modules` directory. GlassFish Server will
413automatically discover these modules. If an administrator installs
414connector modules that contain`Sniffer` implementations while GlassFish
415Server is running, GlassFish Server will pick them up at the next
416deployment request.
417
418[[gkane]][[GSACG00135]][[example-of-adding-container-capabilities]]
419
420Example of Adding Container Capabilities
421~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422
423This example shows a custom container and a web client of the container.
424The example is comprised of the following code:
425
426* Code for the container, which is shown in link:#gkbah[Container
427Component Code]
428* Code for a web client of the container, which is shown in
429link:#gkbcq[Web Client Code]
430
431Code that defines the configuration data for the container component is
432shown in link:adding-configuration-data.html#gkaal[Examples of Adding
433Configuration Data for a Component].
434
435Code for an `asadmin` subcommand that updates the configuration data in
436this example is shown in link:extending-asadmin.html#gkbdf[Example 4-7].
437
438[[gkbah]][[GSACG00238]][[container-component-code]]
439
440Container Component Code
441^^^^^^^^^^^^^^^^^^^^^^^^
442
443The container component code is comprised of the classes and interfaces
444that are listed in the following table. The table also provides a
445cross-reference to the listing of each class or interface.
446
447[width="100%",cols="<50%,<50%",options="header",]
448|==============================================
449|Class or Interface |Listing
450|`Greeter` |link:#gkamr[Example 7-3] +
451|`GreeterContainer` |link:#gkand[Example 7-4] +
452|`GreeterContainer` |link:#gkamm[Example 7-5] +
453|`GreeterDeployer` |link:#gkalo[Example 7-6] +
454|`GreeterSniffer` |link:#gkaks[Example 7-7] +
455|==============================================
456
457
458[[GSACG00066]][[gkamr]]
459
460
461Example 7-3 Annotation to Denote a Container's Component
462
463This example shows the code for defining a component of the `Greeter`
464container.
465
466[source,oac_no_warn]
467----
468package org.glassfish.examples.extension.greeter;
469
470import java.lang.annotation.Retention;
471import java.lang.annotation.RetentionPolicy;
472
473/**
474 * Simple annotation to denote Greeter's component
475 */
476@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
477public @interface Greeter {
478
479 /**
480 * Name to uniquely identify different greeters
481 *
482 * @return a good greeter name
483 */
484 public String name();
485}
486----
487
488[[GSACG00067]][[gkand]]
489
490
491Example 7-4 Application Container Class
492
493This example shows the Java language class `GreeterAppContainer`, which
494implements the `ApplicationContainer` interface.
495
496[source,oac_no_warn]
497----
498package org.glassfish.examples.extension.greeter;
499
500import org.glassfish.api.deployment.ApplicationContainer;
501import org.glassfish.api.deployment.ApplicationContext;
502import org.glassfish.api.deployment.archive.ReadableArchive;
503
504import java.util.List;
505import java.util.ArrayList;
506
507public class GreeterAppContainer implements ApplicationContainer {
508
509 final GreeterContainer ctr;
510 final List<Class> componentClasses = new ArrayList<Class>();
511
512 public GreeterAppContainer(GreeterContainer ctr) {
513 this.ctr = ctr;
514 }
515
516 void addComponent(Class componentClass) {
517 componentClasses.add(componentClass);
518 }
519
520 public Object getDescriptor() {
521 return null;
522 }
523
524 public boolean start(ApplicationContext startupContext) throws Exception {
525 for (Class componentClass : componentClasses) {
526 try {
527 Object component = componentClass.newInstance();
528 Greeter greeter = (Greeter)
529 componentClass.getAnnotation(Greeter.class);
530 ctr.habitat.addComponent(greeter.name(), component);
531 } catch(Exception e) {
532 throw new RuntimeException(e);
533 }
534 }
535 return true;
536 }
537
538 public boolean stop(ApplicationContext stopContext) {
539 for (Class componentClass : componentClasses) {
540 ctr.habitat.removeAllByType(componentClass);
541 }
542 return true;
543 }
544
545 public boolean suspend() {
546 return false;
547 }
548
549 public boolean resume() throws Exception {
550 return false;
551 }
552
553 public ClassLoader getClassLoader() {
554 return null;
555 }
556}
557----
558
559[[GSACG00068]][[gkamm]]
560
561
562Example 7-5 Container Class
563
564This example shows the Java language class `GreeterContainer`, which
565implements the `Container` interface.
566
567[source,oac_no_warn]
568----
569package org.glassfish.examples.extension.greeter;
570
571import org.glassfish.api.container.Container;
572import org.glassfish.api.deployment.Deployer;
573import org.jvnet.hk2.annotations.Service;
574import org.jvnet.hk2.annotations.Inject;
575import org.jvnet.hk2.component.Habitat;
576
577@Service(name="org.glassfish.examples.extension.GreeterContainer")
578public class GreeterContainer implements Container {
579
580 @Inject
581 Habitat habitat;
582
583 public Class<? extends Deployer> getDeployer() {
584 return GreeterDeployer.class;
585 }
586
587 public String getName() {
588 return "greeter";
589 }
590}
591----
592
593[[GSACG00069]][[gkalo]]
594
595
596Example 7-6 Deployer Class
597
598This example shows the Java language class `GreeterDeployer`, which
599implements the `Deployer` interface.
600
601[source,oac_no_warn]
602----
603package org.glassfish.examples.extension.greeter;
604
605import org.glassfish.api.deployment.Deployer;
606import org.glassfish.api.deployment.MetaData;
607import org.glassfish.api.deployment.DeploymentContext;
608import org.glassfish.api.deployment.ApplicationContainer;
609import org.glassfish.api.deployment.archive.ReadableArchive;
610import org.glassfish.api.container.Container;
611import org.jvnet.hk2.annotations.Service;
612
613import java.util.Enumeration;
614
615@Service
616public class GreeterDeployer
617 implements Deployer<GreeterContainer, GreeterAppContainer> {
618
619 public MetaData getMetaData() {
620 return null;
621 }
622
623 public <V> V loadMetaData(Class<V> type, DeploymentContext context) {
624 return null;
625 }
626
627 public boolean prepare(DeploymentContext context) {
628 return false;
629 }
630
631 public GreeterAppContainer load(
632 GreeterContainer container, DeploymentContext context) {
633
634 GreeterAppContainer appCtr = new GreeterAppContainer(container);
635 ClassLoader cl = context.getClassLoader();
636
637 ReadableArchive ra = context.getOriginalSource();
638 Enumeration<String> entries = ra.entries();
639 while (entries.hasMoreElements()) {
640 String entry = entries.nextElement();
641 if (entry.endsWith(".class")) {
642 String className = entryToClass(entry);
643 try {
644 Class componentClass = cl.loadClass(className);
645 // ensure it is one of our component
646 if (componentClass.isAnnotationPresent(Greeter.class)) {
647 appCtr.addComponent(componentClass);
648 }
649 } catch(Exception e) {
650 throw new RuntimeException(e);
651 }
652
653 }
654 }
655 return appCtr;
656 }
657
658 public void unload(GreeterAppContainer appContainer, DeploymentContext context) {
659
660 }
661
662 public void clean(DeploymentContext context) {
663
664 }
665
666 private String entryToClass(String entry) {
667 String str = entry.substring("WEB-INF/classes/".length(), entry.length()-6);
668 return str.replaceAll("/", ".");
669 }
670}
671----
672
673[[GSACG00070]][[gkaks]]
674
675
676Example 7-7 Sniffer Class
677
678This example shows the Java language class `GreeterSniffer`, which
679implements the `Sniffer` interface.
680
681[source,oac_no_warn]
682----
683package org.glassfish.examples.extension.greeter;
684
685import org.glassfish.api.container.Sniffer;
686import org.glassfish.api.deployment.archive.ReadableArchive;
687import org.glassfish.api.admin.config.ConfigParser;
688import org.glassfish.examples.extension.greeter.config.GreeterContainerConfig;
689import org.jvnet.hk2.annotations.Service;
690import org.jvnet.hk2.annotations.Inject;
691import org.jvnet.hk2.component.Habitat;
692import com.sun.enterprise.module.Module;
693
694import java.util.logging.Logger;
695import java.util.Map;
696import java.io.IOException;
697import java.lang.annotation.Annotation;
698import java.lang.reflect.Array;
699import java.net.URL;
700
701/**
702 * @author Jerome Dochez
703 */
704@Service(name="greeter")
705public class GreeterSniffer implements Sniffer {
706
707 @Inject(optional=true)
708 GreeterContainerConfig config=null;
709
710 @Inject
711 ConfigParser configParser;
712
713 @Inject
714 Habitat habitat;
715
716 public boolean handles(ReadableArchive source, ClassLoader loader) {
717 return false;
718 }
719
720 public String[] getURLPatterns() {
721 return new String[0];
722 }
723
724 public Class<? extends Annotation>[] getAnnotationTypes() {
725 Class<? extends Annotation>[] a = (Class<? extends Annotation>[]) Array.newInstance(Class.class, 1);
726 a[0] = Greeter.class;
727 return a;
728 }
729
730 public String getModuleType() {
731 return "greeter";
732 }
733
734 public Module[] setup(String containerHome, Logger logger) throws IOException {
735 if (config==null) {
736 URL url = this.getClass().getClassLoader().getResource("init.xml");
737 if (url!=null) {
738 configParser.parseContainerConfig(
739 habitat, url, GreeterContainerConfig.class);
740 }
741 }
742 return null;
743 }
744
745 public void tearDown() {
746
747 }
748
749 public String[] getContainersNames() {
750 String[] c = { GreeterContainer.class.getName() };
751 return c;
752 }
753
754 public boolean isUserVisible() {
755 return true;
756 }
757
758 public Map<String, String> getDeploymentConfigurations
759 (ReadableArchive source) throws IOException {
760 return null;
761 }
762
763 public String[] getIncompatibleSnifferTypes() {
764 return new String[0];
765 }
766}
767----
768
769[[gkbcq]][[GSACG00239]][[web-client-code]]
770
771Web Client Code
772^^^^^^^^^^^^^^^
773
774The web client code is comprised of the classes and resources that are
775listed in the following table. The table also provides a cross-reference
776to the listing of each class or resource.
777
778[width="100%",cols="<50%,<50%",options="header",]
779|==================================================
780|Class or Resource |Listing
781|`HelloWorld` |link:#gkaki[Example 7-8] +
782|`SimpleGreeter` |link:#gkalf[Example 7-9] +
783|Deployment descriptor |link:#gkaly[Example 7-10] +
784|==================================================
785
786
787[[GSACG00071]][[gkaki]]
788
789
790Example 7-8 Container Client Class
791
792[source,oac_no_warn]
793----
794import components.SimpleGreeter;
795
796import java.io.IOException;
797import java.io.PrintWriter;
Steve Millidge8ef0aa72020-10-25 16:36:38 +0000798import jakarta.servlet.annotation.WebServlet;
799import jakarta.servlet.*;
800import jakarta.servlet.http.*;
Lukas Jungmanndf239082020-04-29 13:37:31 +0200801import jakarta.annotation.Resource;
Vinay Vishal7c4c4fc2019-01-28 12:01:04 +0530802
803
804@WebServlet(urlPatterns={"/hello"})
805public class HelloWorld extends HttpServlet {
806
807 @Resource(name="Simple")
808 SimpleGreeter greeter;
809
810 public void doGet(HttpServletRequest req, HttpServletResponse res)
811 throws IOException, ServletException {
812
813
814 PrintWriter pw = res.getWriter();
815 try {
816 pw.println("Injected service is " + greeter);
817 if (greeter!=null) {
818 pw.println("SimpleService says " + greeter.saySomething());
819 pw.println("<br>");
820 }
821 } catch(Exception e) {
822 e.printStackTrace();
823 }
824 }
825}
826----
827
828[[GSACG00072]][[gkalf]]
829
830
831Example 7-9 Component for Container Client
832
833[source,oac_no_warn]
834----
835package components;
836
837import org.glassfish.examples.extension.greeter.Greeter;
838
839@Greeter(name="simple")
840public class SimpleGreeter {
841
842 public String saySomething() {
843 return "Bonjour";
844 }
845}
846----
847
848[[GSACG00073]][[gkaly]]
849
850
851Example 7-10 Deployment Descriptor for Container Client
852
853[source,oac_no_warn]
854----
855<?xml version="1.0" encoding="UTF-8"?>
856<web-app version="3.1"
857 xmlns="http://xmlns.jcp.org/xml/ns/javaee"
858 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
859 xsi:schemaLocation=
860 "http://xmlns.jcp.org/xml/ns/javaee
861 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
862</web-app>
863----