Services de génération d'URL

Découvrez les services utilisés pour créer des URL dans l'interface SPI de l'état de navigation.

L'interface SPI de l'état de navigation fournit les deux services suivants qui permettent de créer des URL accessibles via l'interface JNDI (Java Naming and Directory Interface):
  • Le service de portail com.ibm.portal.state.service.PortalStateManagerService fournit davantage de services que n'en fournissent les balises du portail. Utilisez la commande PortalStateManagerService pour créer des URL dans les artefacts de portail. Vous pouvez créer des URL dans les artefacts du portail, tels que les thèmes et les habillages (par exemple des balises JSP personnalisées). Vous pouvez aussi l'utiliser dans les artefacts côté serveur qui sont supprimés du traitement de la requête(par exemple Enterprise JavaBeans). Ce service est en dehors du contexte de portlet.
  • Le service com.ibm.portal.portlet.service.PortletStateManagerService prend en charge les portlets compatibles JSR 168 et JSR 286. Utilisez PortletStateManagerService pour créer des URL dans des portlets qui ne peuvent pas être créés à l'aide de l'API de portlet standard. Ce service est destiné aux portlets uniquement.

Ces deux services utilisent une interface commune appelée com.ibm.portal.state.service.StateManagerService, qui fournit les fonctions communes aux deux services. Vous pouvez réutiliser le code de génération des URL dans des thèmes, habillages et portlets s'ils utilisent l'interface commune. Par exemple, vous pouvez utiliser une balise JSP personnalisée, conçue à l'origine pour être utilisée avec les thèmes, dans un JSP spécifique aux portlets, car seule la recherche du service est différente.

Accès au service PortalStateManagerService

Vous pouvez accéder au service PortalStateManagerService via une recherche JNDI en utilisant le nom "portal:service/state/PortalStateManager" pour la recherche. La recherche renvoie une interface com.ibm.portal.state.service.PortalStateManagerServiceHome qui fournit les deux commandes get suivantes permettant d'extraire le service com.ibm.portal.state.service.PortalStateManagerService :
PortalStateManagerService getPortalStateManagerService( HttpServletRequest request, HttpServletResponse response)
Le service qui est renvoyé permet de créer des URL dans les thèmes, les habillages et les balises JSP personnalisées. Toutes les informations relatives au serveur requises pour générer les URL (telles que le nom de l'hôte, le protocole, le port du serveur, le chemin de contexte) sont extraites de la requête du servlet.
PortalStateManagerService getPortalStateManagerService( ServerContext ctx, Locale locale, Profile profile, boolean isProtected, boolean isSecure)
Cette méthode renvoie une interface PortalStateManagerService destinée à une utilisation hors ligne, comme la création d'URL dans des environnements où la requête servlet n'est pas disponible (dans un composant Enterprise JavaBeans par exemple). Pour pouvoir utiliser cette méthode, les informations relatives au serveur (telles que le nom de l'hôte, le protocole, le port du serveur, le chemin de contexte) sont fournies dans un argument ServerContext. L'interface com.ibm.portal.state.accessors.url.ServerContext est l'élément d'abstraction requis pour ce type d'information. Si vous souhaitez créer des URL pointant vers un portail virtuel spécifique, l'objet ServerContext fourni doit désigner ce portail virtuel. L'objet ServerContext désigne ce portail virtuel via le chemin de contexte ou par le nom de l'hôte. Les deux arguments booléens spécifient si les URL doivent par défaut désigner la zone protégée (isProtected) et si les URL créées doivent être par défaut prises en charge par le biais d'une connexion sécurisée (isSecure). Pour prendre en charge la création d'URL de ressource, les arguments locale et profile doivent être fournis. L'argument locale est requis pour créer des URL prenant en charge des ressources spécifiques à l'environnement local, telles que les icônes associées aux différentes langues. L'argument profile correspond au profil du client et permet notamment la vérification des capacités du client.

La durée de vie d'un objet PortalStateManagerService varie selon qu'un service "spécifique à une requête" ou un service "hors ligne" a été demandé. Le service spécifique à une requête est utilisé uniquement pour la durée d'une requête servlet. Pour toutes les requêtes servlet ultérieures, une nouvelle instance du service devra être demandée depuis l'interface home. La durée de vie de l'interface hors ligne PortalStateManagerService correspond à la durée de l'objet ServerContext.

L'objet PortalStateManagerServiceHome obtenu est valide pendant toute la durée de vie du portail. La recherche JNDI ne doit être effectuée qu'une seule fois et vous devez stocker l'objet home extrait en conséquence, par exemple dans une instance ou une variable statique.

L'exemple suivant montre comment accéder au service :
/** the JNDI name to retrieve the PortalStateManagerServiceHome object */
private static final String JNDI_NAME = 
  "portal:service/state/PortalStateManager";

/** PortalStateManagerServiceHome object to retrieve the service from */
private static PortalStateManagerServiceHome serviceHome;

public void useRequestService(final HttpServletRequest request,
                              final HttpServletResponse response) {
  try {
    // get the request-specific service from our home interface
    final StateManagerService service
      = getServiceHome().getPortalStateManagerService(request, response);
    // use the service
    // ...
    // indicate that we do not need it any longer
    service.dispose();
  } catch (Exception e) {
    // error handling
  }
}

public void useOfflineService(final ServerContext ctx,
                              final Locale locale,
                              final Profile profile,
                              final boolean prot,
													 final boolean secure) {
  try {
    // get the offline service from our home interface
    final StateManagerService service
      = getServiceHome().getPortalStateManagerService(ctx, locale, profile, prot, secure);
    // use the service
    // ...
    // indicate that we do not need it any longer
    service.dispose();
  } catch (Exception e) {
    // error handling
  }
}

/**
 * Looks up the PortalStateManagerServiceHome being valid
 * for the lifetime of the portal.
 */
private static PortalStateManagerServiceHome getServiceHome() {
  if (serviceHome == null) {
    try {
      final Context ctx = new InitialContext();
      serviceHome =
        (PortalStateManagerServiceHome) ctx.lookup(JNDI_NAME);
    } catch (Exception e) {
      // error handling
    }
  }
  return serviceHome;
}
Remarque : L'interface PortalStateManagerService est basée sur l'interface générique StateManagerService. Dans la mesure où StateManagerService permet d'étendre les capacités de l'interface com.ibm.portal.Disposable, lorsque vous n'avez plus besoin d'accéder au service, indiquez-le en lançant la méthode dispose(). Désactivez l'interface PortalStateManagerService spécifique à la requête à la fin de la requête servlet traitée.

Accès au service PortletStateManagerService

Vous pouvez accéder au service PortletStateManagerService via JNDI en utilisant le nom de recherche "portletservice/com.ibm.portal.state.service.PortletStateManagerService". La recherche renvoie l'interface générique com.ibm.portal.portlet.service.PortletServiceHome qui fournit la méthode getPortletService(Class) permettant d'obtenir le service PortletStateManagerService. L'instance PortletStateManagerService extraite est valide pendant toute la durée de vie du portail. Vous devez extraire le service de la méthode du portlet et le stocker dans une variable d'instance de portlet. L'exemple suivant montre le code de recherche requis :
public class MyPortlet extends GenericPortlet {

  /** The JNDI name which is needed to lookup the service */
  private static final String JNDI_NAME =
    "portletservice/com.ibm.portal.state.service.PortletStateManagerService";

  /** portlet state manager service */
  protected PortletStateManagerService service;

  /**
   * @see javax.portlet.GenericPortlet#init()
   */
  public void init() throws PortletException {
    super.init();
    try {
      // lookup the portlet state manager service
      final Context ctx = new InitialContext();
      final PortletServiceHome serviceHome = (PortletServiceHome) 
        ctx.lookup(JNDI_NAME);
      service = (PortletStateManagerService) 
        serviceHome.getPortletService(PortletStateManagerService.class);
    } catch (NameNotFoundException e) {
      throw new PortletException(e);
    } catch (NamingException e) {
      throw new PortletException(e);
    }
  }
Vous pouvez utiliser le service réel au sein de la méthode de rendu du portlet pour inclure des URL dans le marquage. Ou vous pouvez utiliser le service dans les méthodes de type helper qui s'appliquent aux modes des portlets obligatoires, telles que doView, doEdit et doHelp) afin d'inclure les URL dans le marquage. Ou utilisez le service dans la méthode processAction pour envoyer un réacheminement à une URL. L'interface PortletStateManagerService fournit les deux méthodes suivantes :
PortletStateManager getPortletStateManager( PortletRequest request, PortletResponse response)
Cette méthode renvoie un objet PortletStateManager que vous pouvez utiliser lors du rendu et du traitement d'actions (par exemple, avec les méthodes processAction, doView, doEdit, etc.) L'interface PortletStateManager ajoute des méthodes pour étendre l'interface StateManagerService générique. Par exemple, cela vous permet de lire directement l'état de navigation du portlet associé à la requête (mode du portlet, état de la fenêtre et paramètres de rendu).
PortletStateManagerController getPortletStateManagerController( ActionRequest request, Action response)
Cette méthode renvoie un contrôleur PortletStateManagerController qui étend les capacités de l'interface PortletStateManager. Le contrôleur PortletStateManagerController fournit des méthodes supplémentaires qui permettent de modifier l'état de navigation du portlet pour la requête actuelle. Et le contrôleur n'est donc accessible que pendant le traitement des actions (par exemple lors de l'exécution de la méthode processAction du portlet).
PortletStateManager et PortletStateManagerController sont tous deux dépendants des requêtes, ce qui signifie que vous ne devez pas stocker de références les concernant dans plusieurs requêtes. Vous devez à la place extraire le service de l'objet PortletServiceHome. Pour indiquer que l'instance PortletStateManager ou PortletStateManagerController extraite n'est plus utilisée dans la portée d'une requête, vous devez démarrer la méthode dispose. La méthode dispose est héritée de l'interface de désactivation qui lui est associée. L'exemple suivant vous montre comment extraire le service de l'objet PortletServiceHome :
/**
 * @see javax.portlet.GenericPortlet#doView(RenderRequest, RenderResponse)
 */
protected void doView(
  final RenderRequest request, final RenderResponse response)
  throws PortletException, IOException {
  response.setContentType(request.getResponseContentType());
  final PrintWriter writer = response.getWriter();
  try {
    // get the request-specific portlet state manager
    final PortletStateManager mgr = service.
      getPortletStateManager(request, response);
    // do something (create URLs etc.)
    // ...
    // indicate that we do not need the portlet state manager any longer
    mgr.dispose();
  } catch (StateException e) {
    throw new PortletException(e);
  }
}

L'interface de base StateManagerService

Les interfaces PortletStateManager et PortalStateManagerService sont basées sur l'interface com.ibm.portal.state.service.StateManagerService, qui offre des fonctionnalités communes aux deux services de génération d'URL. Ces deux services sont généralement utilisés pour créer des URL du type EngineURL, qui prennent en charge l'état de navigation et les URL de ressource. L'interface StateManagerService doit donc être utilisée dans la plupart des cas. Cette interface fournit les deux méthodes suivantes :
URLFactory getURLFactory()
Cette méthode renvoie un objet com.ibm.portal.state.URLFactory qui offre plusieurs méthodes permettant de créer différentes URL. Vous pouvez obtenir davantage d'informations sur URLFactory.
AccessorFactory getAccessorFactory(Class accessorFactoryClass)
Cette méthode permet d'accéder aux différentes fabriques ID d'accès. Pour plus d'informations, voir Interface SPI de l'accesseur . Vous devez utiliser l'interface de classe d'ID d'accès appropriée comme argument de méthode pour extraire une certaine classe d'ID d'accès, l'objet Class.
Remarque : Lorsque vous utilisez le service PortletStateManagerService, seules les classes d'ID d'accès SelectionAccessorFactory, PortletAccessorFactory, PortletTargetAccessorFactory, SoloAccessorFactory, ThemeTemplateAccessorFactory, LocaleAccessorFactory, StatePartitionAccessorFactory et ExpansionStatesAccessorFactory peuvent être utilisées.
En règle générale, vous exécutez une requête pour extraire un objet EngineURL de la classe URLFactory, puis vous modifiez l'état de navigation en fonction de la sémantique de l'URL requise. Pour effectuer cette étape, appelez la méthode getState() de EngineURL pour extraire l'objet StateHolderController requis pour modifier l'état de navigation via l'interface SPI d'ID d'accès. Le fragment de code ci-après illustre parfaitement ce type d'utilisation. L'exemple suivant vous montre comment appeler la méthode getState() de l'objet EngineURL :
protected EngineURL createPageLink(final ObjectID pageID)
  throws StateException {
  // get the URL factory from the state manager service
  final URLFactory urlFactory = service.getURLFactory();
  try {
    // get a EngineURL from the factory; maintain navigational state
    final EngineURL url = urlFactory.newURL(null);
    final SelectionAccessorFactory selectionFct = (SelectionAccessorFactory) 
      service.getAccessorFactory(SelectionAccessorFactory.class);
    // get a selection controller that operates on the URL-specific state
    final SelectionAccessorController selectionCtrl = 
      selectionFct.getSelectionAccessorController(url.getState());
    try {
      // modify page selection and return URL
      selectionCtrl.setSelection(pageID);
      return url;
    } finally {
      selectionCtrl.dispose();
    }
  } finally {
    urlFactory.dispose();
  }
}
Dans l'exemple de code précédent, la méthode newURL(Constants.Clone) de la classe URLFactory est utilisée. Cependant, la classe URLFactory offre d'autres méthodes pour créer des objets EngineURLs ainsi que des URL de ressource. La liste ci-après vous fournit une description complète de l'interface URLFactory :
EngineURL newURL(Constants.Clone type)
Utilisez cette méthode pour créer une interface EngineURL dans la mesure où elle convient à la plupart des cas. La méthode fournit un objet EngineURL, qui fait référence à l'argument StateHolder représentant l'état de navigation de la requête courante. L'argument type spécifie comment l'argument StateHolder associé à la requête doit être cloné pour l'URL devant être créée. Il existe quatre constantes de clonage prédéfinies :
  • SMART_COPY indique qu'une copie vide StateHolder doit être créée. La copie enregistre les modifications d'état appliquées à cet objet EngineURL spécifique, plutôt que de copier tous les nœuds dans le modèle de document pour créer le clone. SMART_COPY est la valeur par défaut. Ne rien spécifier équivaut à sélectionner SMART_COPY. Cette méthode de clonage permet également de créer des URL "delta" relatives.
  • DEEP_COPY permet d'obtenir une copie complète de l'argumentStateHolder associé à la requête, par exemple chaque nœud et la totalité de la hiérarchie des nœuds sont clonés. En revanche, cette méthode ne permet pas de créer des URL delta.
  • EMPTY_COPY indique que le contenu de l'argument StateHolder associé à la requête doit être effacé, par exemple, l'objet EngineURL créé est basé sur un état vide. Toute interaction avec ce type d'URL se traduit par la perte de l'état de navigation des précédentes interactions.

Si la classe URLFactory n'a pas accès à la requête courante, un nouvel argument StateHolder vide est créé de manière interne. Dans ce cas, l'argument type n'a aucun effet.

EngineURL newURL(StateHolder state, Constants.Clone type)
Cette seconde méthode getURL requiert que l'argument StateHolder sur lequel l'objet EngineURL est basé soit transmis de manière explicite. L'argument type fait donc référence à cet argument StateHolder spécifique. Utilisez cette méthode lorsque l'URL devant être créée doit intégrer un argument StateHolder défini par le biais d'un programme. Le fait de cliquer sur cette URL se traduira par la perte de l'état de navigation des précédente interactions avec le portail.
EngineURL newURL(URLContext ctx, Constants.Clone type)
Cette variante vous permet de spécifier si l'URL créée doit être absolue, relative ou relative au serveur. Cette action peut être réalisée via la transmission d'une interface urlcontext. Cette interface doit être mise en œuvre en conséquence. Par exemple, si l'URL doit être une URL absolue, la méthode isAbsolute() doit renvoyer la valeur true tandis que les méthodes isRelative() et isServerRelative() doivent renvoyer la valeur false. Dans la mesure où cette méthode ne nécessite pas d'argument StateHolder explicite, l'objet EngineURL qui doit être créé intègre l'argument StateHolder extrait de la requête. Pour réduire la taille du marquage, il est recommandé de transmettre un URLContext qui autorise les URL relatives. Si la classe URLFactory n'a pas accès à la requête courante, un nouvel argument StateHolder vide est créé de manière interne. Dans ce cas, l'argument type n'a aucun effet.
EngineURL newURL(URLContext ctx, Constants.Clone type)
Cette méthode est la contrepartie de la précédente méthode et utilise un argument StateHolder défini comme argument explicite.
DisposableURL newResourceURL( String name, PortalResources.Type type)
Cette méthode crée une URL qui désigne un ressource générique. Le nom de fichier et le type de ressource identifient la ressource. La recherche de la ressource requiert des informations propres à la requête, telles que l'environnement local courant, le dispositif client et le nom du marquage dans le compte (si la requête est disponible). L'interface com.ibm.portal.state.accessors.url.PortalResources fournit plusieurs constantes utiles pour le type de ressource représentant des ressources telles que des fichiers, des sons, des icônes et des règles grammaticales vocales.
DisposableURL newResourceURL( String name, PortalResources.Type type, PortalResources.State state)
Cette méthode crée une URL qui désigne un ressource générique. Le nom de fichier et le type de ressource identifient la ressource. Elle peut également contenir un état de la ressource permettant d'affiner davantage la recherche de la ressource. La recherche de la ressource prend en compte des informations supplémentaires fournies par la requête (si ces informations sont disponibles). Il s'agit de l'environnement local, du dispositif client, du marquage choisi pour le client et le nom du thème.
Remarque : Une URL absolue est une URL complète contenant le protocole, le nom de l'hôte et le port. Dans le cas d'une URL relative au serveur, le navigateur fournit le protocole, le nom de l'hôte et le port. Dans le cas d'une URL relative, le navigateur ajoute l'URL à l'URL de requête courante ou à la valeur de la balise de base HTML (s'il en existe une). Les URL relatives au serveur et les URL relatives ne peuvent pas être appliquées. Par exemple, dans le cas d'un changement de protocole de "http" à "https", l'URL générée sera une URL absolue.

Modification du nom d'hôte des URL absolues

Vous pouvez modifier le nom d'hôte des URL absolues pour des raisons de sécurité. Par exemple, vous pouvez effectuer cette modification si le DOM d'une application, tel un portlet, s'exécute dans un iframe et que vous ne voulez pas que le code JavaScript dans cet iframe puisse accéder au DOM du document HTML. Si toutes les URL dans cet iframe sont absolues et que le nom d'hôte de ces URL est différent de celui d'où émane le document, l'iframe est accessible uniquement à lui-même. En d'autres mots, il ne peut pas manipuler ni accéder au reste du DOM du document. Pour garantir cette action, créez toutes les URL dans le portlet à l'aide de la SPI d'état de navigation contenant des URL absolues. Le portlet doit alors définir un nom d'hôte virtuel, qui doit être redirigé par un proxy vers le serveur de portail. De plus, le portlet doit vérifier que toutes les demandes dans lesquelles les adresses URL absolues requises doivent être générées contiennent un en-tête de demande spécial. L'en-tête de demande indique au portail le nom de l'hôte virtuel. Les en-têtes sont les suivants :
com.ibm.lotus.openajax.virtualhost
Utilisez cet en-tête pour définir le nom d'hôte de toutes les URL absolues générées à la valeur de cet en-tête de demande.
com.ibm.lotus.openajax.virtualport
Utilisez cet demande pour définir le port de toutes les URL absolues générées à la valeur de cet en-tête de demande.