Logo Oracle Deutschland   Application Express Community
Eigene Bereitstellungsverfahren für APEX Workspaces einrichten

APEX ist bereits seit dem ersten Tag für Hosting-Umgebungen ausgelegt. Wie jedermann auf dem öffentlichen Demoserver apex.oracle.com selbst ausprobieren kann, kann ein Workspace in Selbstbedienung beantragt werden. Nach der Genehmigung durch den Administrator wird der Workspace einrichtet und der Entwickler kann mit der Arbeit beginnen.

"Beantragen" eines neuen APEX-Workspace

Abbildung 1: "Beantragen" eines neuen APEX-Workspace

Dieser von APEX mit ausgelieferte Bereitstellungsprozeß ist zwar sehr bequem - in vielen Fällen passt er jedoch nicht auf die Bedürfnisse im Unternehmen ...

  • Der Vorgesetzte muss den Workspace genehmigen und nicht der APEX-Administrator.
  • Die von APEX standardmäßig erfassten Angaben reichen nicht aus - man möchte ggfs. eine Kostenstelle oder einen Abteilungsnamen erfragen.
  • Die Seiten zur Beantragung eines Workspace soll durch Login geschützt werden
  • Die Email-Adresse soll nicht frei eingebbar sein, sondern aus dem Login abgeleitet werden
  • Und und und ...

Fast alle Anforderungen dieser Art ließen sich mit einer eigenen APEX-Anwendung problemlos abdecken - die Anforderungen könnten in einer eigenen Tabelle abgelegt werden. Zur konkreten Einrichtung des Workspace wird dann allerdings ein automatisierter Prozeß benötigt.

Bereits vor einigen APEX-Versionen wurde das PL/SQL-Paket APEX_INSTANCE_ADMIN eingeführt; damit können APEX-Workspaces auch aus PL/SQL heraus verwaltet werden. Die Notwendigkeit für dieses Paket kam mit der Runtime-Only-Installation auf - wenn keine APEX-Entwicklungsumgebung mehr da ist, ist auch keine APEX-Administrationsumgebung (Workspace INTERNAL) mehr da; die Aufgaben müssen also mit APEX_INSTANCE_ADMIN erledigt werden.

Im folgenden wird exemplarisch vorgestellt, wie ein sehr einfacher Prozess zum Einrichten eines APEX-Workspaces implementiert werden kann. Dieser kann dann natürlich so lange ausgebaut werden, bis konkrete Anforderungem im Unternehmen erfüllt sind.

  • Die Anwendung zum Beantragen eines Workspace wird durch einen Login geschützt
  • Die Mailadresse wird aus dem APEX-Usernamen Login abgeleitet (&APP_USER.@meinefirma.de)
  • Der Workspace-Name wird generiert
  • Es wird immer ein neues Datenbankschema erstellt - der Name wird generiert
  • Alle Datenbankschemas bekommen TS_APEX_WORKSPACES als Tablespace zugewiesen
  • Die Tablespace-Quota wird einheitlich auf 25MB gesetzt

Zunächst wird also eine Tabelle benötigt, in welche die Anforderungen gespeichert werden. Das folgende SQL-Skript legt die Tabelle an. Lassen Sie es im Parsing-Schema des APEX-Workspace, in dem die Web-Oberfläche zum Beantragen eines Workspace liegen soll, laufen. Damit der gesamte Prozess funktioniert, muss diesem Parsing Schema allerdings die Rolle APEX_ADMINISTRATOR_ROLE zugewiesen werden.

create table tab_apex_workspace_requests(
  id              number(10),
  workspace_name  varchar2(255), 
  admin_userid    varchar2(255) not null,
  admin_email     varchar2(255) not null,
  admin_name      varchar2(255) not null,
  admin_vorname   varchar2(255) not null,
  admin_password  varchar2(6),   
  zeitstempel     date          not null,
  status          varchar2(20)  default 'REQUEST',
  message         varchar2(4000),
  constraint pk_apex_ws_req primary key (id),
  constraint ch_apex_ws_req_status check (status in ('REQUEST', 'WORKING', 'ERROR', 'APPROVED'))
)
/

create sequence seq_apex_workspace_request start with 10
/

create or replace trigger tr_apex_workspace_request
before insert on tab_apex_workspace_requests
for each row
begin
  :new.id := seq_apex_workspace_request.nextval;
  :new.zeitstempel := sysdate;
  :new.status := 'REQUEST';
end;
/
sho err

Erstellen Sie danach eine APEX-Anwendung mit einer Formularseite. Das Formular sollte Eingabefelder für Namen und Vornamen enthalten; die Felder für Email sowie für APEX-User-ID sollten auf Read Only gestellt werden. Das "Generieren" der Emailadresse könnte in einfachen Fällen mit mit einer Belegung des Default ("&APP_USER.@meinefirma.de") erreicht werden; komplexere Fälle erfordern ein wenig PL/SQL-Logik. Am besten verwenden Sie nicht den APEX-Formularassistenten - legen Sie die Formularfelder einzeln an und fügen Sie die Daten mit einem PL/SQL-Prozess in die Tabelle ein. Eine Anwendung zur Illustration stellen wir hier zum Download bereit.

Das fertige Formular könnte wie in Abbildung 2 aussehen. Erstellen Sie dann einen Bericht, der alle Anforderungen des angemeldeten Nutzers anzeigt; das SQL hierfür ist recht einfach:

select * 
from tab_apex_workspace_requests 
where admin_userid = :APP_USER
Eigenes Formular zum Beantragen eines APEX-Workspace

Abbildung 2: Eigenes Formular zum Beantragen eines APEX-Workspace

Als nächstes wird die PL/SQL-Prozedur erstellt, die anhand dieser Angaben den APEX-Workspace erstellt. Dazu müssen folgende Schritte ausgeführt werden.

  • Ein Passwort für den APEX-Nutzer als auch für das Datenbankschema muss generiert werden
  • Ein neues Datenbankschema muss erstellt werden (CREATE USER)
  • Die nötigen Privilegen wie CREATE TABLE, CREATE PROCEDURE und andere müssen vergeben werden
  • Der Workspace muss mit APEX_INSTANCE_ADMIN erstellt werden
  • Das Benutzerkonto ADMIN muss im neuen Workspace eingerichtet werden

Diese Aktivitäten sind im PL/SQL-Paket PKG_WORKSPACE_PROVISIONING zusammengefasst. Spielen Sie es ebenfalls ins Parsing-Schema des APEX-Workspace ein; dieses muss jedoch EXECUTE-Privilegien auf APEX_040000.APEX_INSTANCE_ADMIN erhalten. Tatsächlich ausgeführt wird es später mittels eines Scheduler-Jobs als SYS.

create or replace package pkg_workspace_provisioning 
is
  procedure create_requested_workspaces;
end pkg_workspace_provisioning;
/
sho err

create or replace package body pkg_workspace_provisioning  
is
  C_DEFAULTTS constant varchar2(30) := 'TS_APEX_WORKSPACES';
  C_TS_QUOTA  constant varchar2(30) := '25M';

  function generate_password return varchar2 is
    v_consonants varchar2(21) := 'bcdfghjklmnpqrstvwxyz';
    v_vocals     varchar2(5)  := 'aeiou';
    v_password   varchar2(6)  := '';
  begin
    v_password := v_password || substr(v_consonants, round(dbms_random.value(1,21)), 1);
    v_password := v_password || substr(v_vocals, round(dbms_random.value(1,5)), 1);
    v_password := v_password || substr(v_consonants, round(dbms_random.value(1,21)), 1);
    v_password := v_password || substr(v_vocals, round(dbms_random.value(1,5)), 1);
    v_password := v_password || substr(v_consonants, round(dbms_random.value(1,21)), 1);
    v_password := v_password || substr(v_vocals, round(dbms_random.value(1,5)), 1);
    return v_password;
  end generate_password;

  procedure create_schema(
    p_schemaname varchar2,
    p_password   varchar2
  ) is 
  begin
    execute immediate 'create user '||p_schemaname|| ' identified by '||p_password||' default tablespace '||C_DEFAULTTS;
    execute immediate 'alter user '||p_schemaname|| ' quota '||C_TS_QUOTA||' on '||C_DEFAULTTS;
    execute immediate 'grant create operator to '||p_schemaname;
    execute immediate 'grant create cluster to '||p_schemaname;
    execute immediate 'grant create dimension to '||p_schemaname;
    execute immediate 'grant create indextype to '||p_schemaname;
    execute immediate 'grant create any context to '||p_schemaname;
    execute immediate 'grant create table to '||p_schemaname;
    execute immediate 'grant create sequence to '||p_schemaname;
    execute immediate 'grant create view to '||p_schemaname;
    execute immediate 'grant create session to '||p_schemaname;
    execute immediate 'grant create synonym to '||p_schemaname;
    execute immediate 'grant create type to '||p_schemaname;
    execute immediate 'grant create trigger to '||p_schemaname;
    execute immediate 'grant create procedure to '||p_schemaname;
    execute immediate 'grant create materialized view to '||p_schemaname;
    execute immediate 'grant create job to '||p_schemaname;
    execute immediate 'grant alter session to '||p_schemaname;
  end create_schema;

  procedure create_workspace(
    p_workspace    in varchar2,
    p_password     in varchar2,
    p_schemaname   in varchar2,
    p_admin_email  in varchar2,
    p_admin_vname  in varchar2,
    p_admin_nname  in varchar2
  ) is 
    v_wsid      number;
    pragma autonomous_transaction;
  begin
   wwv_flow_api.set_security_group_id(p_security_group_id=> 10);
   apex_instance_admin.add_workspace(
     P_WORKSPACE            => p_workspace,
     P_PRIMARY_SCHEMA       => p_schemaname,
     P_ADDITIONAL_SCHEMAS   => p_schemaname
   );
   commit;

   select workspace_id into v_wsid
   from apex_workspaces
   where workspace = p_workspace;

   wwv_flow_api.set_security_group_id(p_security_group_id => v_wsid);

   apex_util.create_user(
     p_user_name       => 'ADMIN',
     p_web_password    => p_password,
     P_DEVELOPER_PRIVS => 'ADMIN:CREATE:DATA_LOADER:EDIT:HELP:MONITOR:SQL',  
     p_first_name      => p_admin_vname,
     p_last_name       => p_admin_nname,
     p_email_address   => p_admin_email,
     p_default_schema  => p_schemaname
   );
   commit;

   apex_instance_admin.enable_workspace(
     P_WORKSPACE       => p_workspace
   );
   commit;
  end create_workspace;
  
  procedure create_requested_workspaces is 
    pragma autonomous_transaction;

    v_schemaname varchar2(30);
    v_workspace  varchar2(30);
    v_password   varchar2(10);

    v_message    varchar2(4000);
  begin
    for i in (
      select * from tab_apex_workspace_requests where status = 'REQUEST'
    ) loop
      v_password   := generate_password;
      v_workspace  := 'APEXWS_'||i.id;
      v_schemaname := 'APEXWS_'||i.id;

      update tab_apex_workspace_requests set 
        status         = 'WORKING' ,
        workspace_name = v_workspace,
        admin_password = v_password
      where id = i.id;
      commit;
      begin
        create_schema(v_schemaname, v_password);
        create_workspace(
          p_workspace    => v_workspace,
          p_password     => v_password,
          p_schemaname   => v_schemaname,
          p_admin_email  => i.admin_email,
          p_admin_vname  => i.admin_vorname,
          p_admin_nname  => i.admin_name
        );
        update tab_apex_workspace_requests set status='APPROVED' where id = i.id;
        commit;
      exception 
        when others then
          v_message := sqlerrm;
          update tab_apex_workspace_requests set status='ERROR', message = v_message
          where id = i.id;
          commit;
      end;
      /* Hier noch eine Email mit APEX_MAIL senden */
    end loop;
  end create_requested_workspaces;
end pkg_workspace_provisioning;
/
sho err

Die Prozedur PKG_WORKSPACE_PROVISIONING.CREATE_REQUESTED_WORKSPACES muss nun regelmäßig ausgeführt werden - dafür sorgt ein Hintergrund-Job, der mit dem Datenbank-Scheduler eingerichtet wird. Der Job muss ebenfalls als SYS laufen - das folgende Beispiel richtet den Job so ein, dass er alle fünf Minuten läuft und ausstehende Anforderungen abarbeitet. Mit DBMS_SCHEDULER.DROP_JOB können Sie den Job wieder löschen.

begin
  dbms_scheduler.create_job(
    job_name            => 'APEX_AUTOAPPROVE_JOB',
    job_type            => 'PLSQL_BLOCK',
    job_action          => 'begin {APEX-Parsing-Schema}.pkg_workspace_provisioning.create_requested_workspaces; end;',
    number_of_arguments => 0,
    start_date          => to_timestamp('2011-02-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
    repeat_interval     => 'FREQ=MINUTELY; INTERVAL=5',
    end_date            => null,
    job_class           => 'DEFAULT_JOB_CLASS',
    enabled             => true,
    auto_drop           => true,
    comments            => null
  );
end;
/
sho err

Tragen Sie nun einen "Workspace-Request" in das Formular der APEX-Anwendung ein und verfolgen Sie im Bericht den Status. Nach einigen Minuten wird der Status zuerst auf WORKING und dann auf APPROVED gestellt. Anschließend ist der Workspace eingerichtet (Abbildung 3).

Verfolgung des Bereitstellungs-Status im APEX-Bericht

Abbildung 3: Verfolgung des Bereitstellungs-Status im APEX-Bericht

Das erstmalige Login läuft wie immer ab. Zuerst muss das Standardpasswort geändert werden und danach kann man im Workspace arbeiten.

Erstmaliger Login in den neuen APEX-Workspace

Abbildung 4: Erstmaliger Login in den neuen APEX-Workspace

Dieses einfache Beispiel lässt sich natürlich weiter denken; so könnte man durchaus verschiedene Workspace-Größen denkbar; das Formular könnte (analog zum Prozess auf apex.oracle.com) verschiedene Größen zur Auswahl anbieten. Technisch würde die Tablespace-Quota von 25M, die im Beispiel mit einer PL/SQL-Konstante "hart" kodiert ist, dynamisch gestaltet. Auch Genehmigungsprozesse oder die Kombination mit einem Abrechnungsmodul ist denkbar. APEX macht das Erstellen der "Provisioning-Anwendung", wie immer, sehr einfach.

Mehr Informationen

  • Dokumentation: APEX_INSTANCE_ADMIN
  • Hintergrund-Jobs mit DBMS_SCHEDULER
  • Zurück zur Community-Seite