#!/usr/local/bin/perl
#
# ncompjp2.pl
# 
# Copyright (c) 2005, 2007, Oracle. All rights reserved.  
#
#    NAME
#      ncompjp2.pl - NCOMP the JPEG2000 codec installed by initjp2.sql
#
#    DESCRIPTION
#      NCOMPs the installed JPEG2000 codec. Using the Oracle NCOMP 
#      utility to convert the ImageIO JPEG2000 codec from Java into 
#      native libraries greatly improves performance. Please see 
#      "Oracle Database Java Developer's Guide" for more information 
#      about NCOMP.
#
#    NOTES
#      This script should be run after initjp2.sql. See
#      README_JPEG2000.txt or initjp2.sql for detailed information on
#      how to install the JPEG2000 codec. 
#
#      This script requires that your platform supports the Oracle 
#      Java Accelerator tool NCOMP.
#
#      Usage: 
#        perl ncompjp2.pl -u <JP2SCHEMA name> -d <projectDir> -h
# 
#        Arguments:
#
#         -u : JPEG2000 schema name. JP2SCHEMA is ORDJP2K by default 
#              unless it is overridden in initjp2.sql. This argument 
#              is required.
#         -d : Specifies the full path for the NCOMP project directory. 
#              This directory must exist. The tool will not create this 
#              directory for you.  This argument is required.
#         -h : help message. This argument is optional.
#
#      Prerequisites for running the script:
#
#      1. Database is up and environment variable ORACLE_HOME is set 
#
#      2. SQL*Plus can be run from command prompt
#
#      3. PATH environment variable includes the directory where PERL 
#         executable resides
#
#      4. NCOMP project directory exists 
#      
#      5. Satisfy the following requirements for running the NCOMP
#         utility. Please see "Oracle Database Java Developer's Guide" 
#         for more details.
#
#        a. Install a C compiler for the intended platform on the
#           computer where you are running NCOMP.
#        b. Verify that the correct compiler and linker commands are 
#           referenced within the Settings_os.properties file located
#           in the <ORACLE_HOME>/javavm/jahome directory. If the
#           settings are not correct, it's possible to override them
#           by creating a file called Settings_os_PRODUCT.properties
#           in the NCOMP project directory. Any settings in this file
#           override the global settings. For example, on Windows, the
#           Settings_os.properties, by default, sets:
#             visual.c.home = c:/devstudio/vc
#           If your VISUAL C is installed under:
#             C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7
#           you can create Settings_os_PRODUCT.properties with one
#           line as:
#  visual.c.home = "C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7"
#           NCOMP will then pick up the compiler and linker under the
#           correct directory.
#
#           Note: on Windows, if there are spaces in the
#           "visual.c.home" path string, put double quotes (") around
#           the string as in the above example.
#
#
#      This script prompts user to enter the SYSDBA password. 
#
#      This script prints out "JPEG2000 library NCOMP succeeds!"
#      if NCOMP succeeds, otherwise "JPEG2000 library NCOMP problems
#      detected!". When NCOMP fails, the content of the JP2SCHEMA's 
#      jaccelerator$dlls and jaccelerator$dll_errors tables are
#      printed out. These two tables are populated by NCOMP to
#      record the deployment results and errors. 
#      Each row in the jaccelerator$dlls table represents a shared
#      library. If the STATUS column is "installed", then the
#      library is ncomped successfully.
#
#      Under the NCOMP project directory, besides the ncomp.log
#      generated by the NCOMP utility, this script also saves the 
#      NCOMP's standard error to a log file named ncompjp2.log.
#      When NCOMP fails, check these two log files for detailed error
#      information.
#
#      Note: if "JPEG2000 library NCOMP problems detected!" shows up,
#      you should check ncomp.log first to find out whether the 
#      C compiler reference is right. If the C compiler or linker
#      cannot be found, ncomp.log will contain errors like "got 
#      java.io.IOException: CreateProcess".
# 

use Cwd;

#
# Read in command-line options
#
use Getopt::Std;
%options=();
getopts("u:d:h",\%options) or usage();

usage() if defined $options{h};
usage() if !defined $options{u};
usage() if !defined $options{d};

$JP2SCHEMA = "\U$options{u}";
$PROJECTDIR = $options{d}; 

#
# Check environment variable
#
$ORACLE_HOME=$ENV{ORACLE_HOME} or die "Enviroment variable ORACLE_HOME is undefined!\n";

$PSEP='/';
$PSEP='\\' if($ENV{OS} =~ /Win/i);

$ORG_JAVA_HOME=$ENV{JAVA_HOME};
$ENV{JAVA_HOME}=$ORACLE_HOME."$PSEP"."jdk15";

# 
# cd to the projectDir 
#
-d $PROJECTDIR or die "NCOMP project directory does not exist!\n";
chdir $PROJECTDIR;

# 
# Copy jai_imageio.jar to the projectDir directory
#
use File::Copy;
$JP2JAILOC = "$ORACLE_HOME"."$PSEP"."ord"."$PSEP"."jlib"."$PSEP"."jai_imageio.jar";
copy($JP2JAILOC, "jai_imageio.jar") or die "Copy $JP2JAILOC to current directory failed\n";

#
# Create the log file
#
$logfilename="ncompjp2.log";
$logh="filehandler";
open ($logh, ">> $logfilename") || die ("Can't open file: \"$logfilename\"");
print $logh "=====================================\n";
print $logh "The JPEG2000 NCOMP Process starts ...\n";

#
# Create a perl script to be called from the following generated sql file 
# to perform NCOMP
#
$tmppl = "tmp.pl";
$fh="filehandler";
open $fh, ">$tmppl";
@pl = << "EOF";
#!/usr/local/bin/perl
\$logfilename="$logfilename";
\$logh="filehandler";
open (\$logh, ">> \$logfilename") || die ("Can't open file: \\\"\$logfilename\\\"");
\$ncompcmd = "ncomp -u \@ARGV[0]/\@ARGV[0] jai_imageio.jar";
print \$logh `\$ncompcmd 2>&1`;
EOF

print $fh @pl;
close($fh);

#
# Create a sql file to prompt for SYSDBA password and
# grant required NCOMP permissions to the JP2SCHEMA,
# perform NCOMP by calling the generated perl script, 
# output whether NCOMP succeeds, revoke granted permissions 
# from JP2SCHEMA, and cleanup leftover NCOMP litter
# 
$ncompjp2sql = "ncompjp2.sql";
open $fh, ">$ncompjp2sql";
@sql = << "EOF";
whenever sqlerror exit 2;
accept pswd char format a30 prompt 'Please enter SYSDBA password: ' hide
connect sys/&pswd as sysdba;
ALTER SESSION SET CURRENT_SCHEMA= "$JP2SCHEMA";

grant javaSysPriv, java_deploy, connect, resource to $JP2SCHEMA;
alter user $JP2SCHEMA account unlock;
alter user $JP2SCHEMA identified by $JP2SCHEMA;

connect $JP2SCHEMA/$JP2SCHEMA
declare
  g_null char(1);
begin
  select null into g_null from user_tables where table_name='JACCELERATOR\$DLLS';
  execute immediate 'delete from jaccelerator\$dlls';
exception
  when no_data_found then
    -- do nothing
    null;
end;
/

declare
  g_null char(1);
begin
  select null into g_null from user_tables where table_name='JACCELERATOR\$DLL_ERRORS';
  execute immediate 'delete from jaccelerator\$status';
  execute immediate 'delete from jaccelerator\$dll_errors';
exception
  when no_data_found then
    -- do nothing
    null;
end;
/

declare
  g_null char(1);
begin
  select null into g_null from user_tables where table_name='JACCELERATOR\$STATUS';
  execute immediate 'delete from jaccelerator\$status';
exception
  when no_data_found then
    -- do nothing
    null;
end;
/

host perl tmp.pl $JP2SCHEMA

connect $JP2SCHEMA/$JP2SCHEMA
CREATE OR REPLACE PROCEDURE ordvalidate_jp2ncomp 
authid current_user
IS
  good_dll_count      number;
BEGIN
  select count(*) into good_dll_count from jaccelerator\$dlls 
    where status = 'installed';

  if (good_dll_count = 44) then
    dbms_output.put_line('JPEG2000 library NCOMP succeeds!');
  else
    dbms_output.put_line('JPEG2000 library NCOMP problems detected!');
    dbms_output.put_line(good_dll_count || ' good dlls out of 44 expected good dlls');
    dbms_output.put_line('Dumping contents of jaccelerator\$dlls!');
    dbms_output.put_line('select timestamp, status, dll_name from ' 
                          || 'jaccelerator\$dlls!');
    FOR ob IN (SELECT timestamp, status, dll_name FROM jaccelerator\$dlls) LOOP
      dbms_output.put_line ( RPAD(ob.timestamp,20) || ob.status || ' ' 
                            || RPAD(ob.dll_name, 80) );
    END LOOP;
    dbms_output.put_line(' ');
    dbms_output.put_line('Dumping contents of jaccelerator\$dll_errors!');
    dbms_output.put_line('select timestamp, problem, class_name, dll_name from ' 
                          || 'jaccelerator\$dll_errors!');
    FOR ob IN (SELECT timestamp, problem, class_name, dll_name FROM jaccelerator\$dll_errors) LOOP
      dbms_output.put_line ( RPAD(ob.timestamp,20) || RPAD(ob.problem, 30) || ' ' ||
                            RPAD(ob.class_name,85) || ' ' || RPAD(ob.dll_name, 80) );
    END LOOP;
  end if;
END; 
/
show errors;
set serveroutput on;
set linesize 220;
exec ordvalidate_jp2ncomp();
set serveroutput off;
drop PROCEDURE ordvalidate_jp2ncomp;

connect sys/&pswd as sysdba
revoke javaSysPriv, java_deploy, connect, resource from $JP2SCHEMA;

declare
  -- note that we need both cursors here because some java files are
  -- compiled within the javavm, so you can't drop those derived classes
  -- directly
  cursor src_curs is 
   select object_name
   from all_objects,javasnm
   where owner = '$JP2SCHEMA' and 
         object_type = 'JAVA SOURCE' and
         short(+) = object_name and
         (nvl(longname, object_name) like 'oracle/jaccelerator%' or
          nvl(longname, object_name) like 'oracle/aurora/deploy%');

  cursor cls_curs is 
   select object_name
   from all_objects,javasnm
   where owner = '$JP2SCHEMA' and 
         object_type = 'JAVA CLASS' and
         short(+) = object_name and
         (nvl(longname, object_name) like 'oracle/jaccelerator%' or
          nvl(longname, object_name) like 'oracle/aurora/deploy%');
begin
  for rec in src_curs loop
    -- drop java source files
    execute immediate 'drop java source $JP2SCHEMA."' || rec.object_name || '"';
  end loop;

  for rec in cls_curs loop
    -- drop java class files
    execute immediate 'drop java class $JP2SCHEMA."' || rec.object_name || '"';
   end loop;

  commit;
end;
/

declare
  cursor curs is 
   select object_name
   from all_procedures
   where owner = '$JP2SCHEMA' and 
         authid='DEFINER' and 
         object_name like 'JACCELERATOR%';
begin
  for rec in curs loop
     execute immediate 'drop function $JP2SCHEMA."' || rec.object_name || '"';
  end loop;

  commit;
end;
/

alter user $JP2SCHEMA account lock;
alter user $JP2SCHEMA password expire;
exit;
EOF

print $fh @sql;
close($fh);

#
# Run the sql script and check return status
#
system("sqlplus \/nolog \@$ncompjp2sql");
$status = $? >> 8;
if ($status != 0)
{
  die "Couldn't connect as SYSDBA or the $JP2SCHEMA schema does not exist!\n";
}

#
# Delete the generated sql and perl scripts
#
unlink $ncompjp2sql;
unlink $tmppl;

#
# Reset environment variable JAVA_HOME
#
$ENV{JAVA_HOME}=$ORG_JAVA_HOME;

#
# Message about this program and how to use it
#
sub usage()
{
    print STDOUT << "EOF";

This program ncomps the installed JPEG2000 codec.

usage: $0 -u <JP2SCHEMA name> -d <projectDir> [-h]

 -u        : JPEG2000 schema name. JP2SCHEMA is ORDJP2K by default 
             unless it is overridden in initjp2.sql. This argument 
             is required.
 -d        : Specifies the full path for the NCOMP project directory. 
             This directory must exist. The tool will not create this 
             directory for you. This argument is required.
 -h        : help message. This argument is optional.

EOF
    exit;
}


