blob: 64c38e399838d49dc4d2e902a6af69e3f3ed769d [file] [log] [blame]
#*******************************************************************************
#* Copyright (c) 2011 Forschungszentrum Juelich GmbH.
#* All rights reserved. This program and the accompanying materials
#* are made available under the terms of the Eclipse Public License v1.0
#* which accompanies this distribution, and is available at
#* http://www.eclipse.org/legal/epl-v10.html
#*
#* Contributors:
#* Wolfgang Frings (Forschungszentrum Juelich GmbH)
#*******************************************************************************/
package LML_gen_table;
my($debug)=0;
use strict;
use Data::Dumper;
use Time::Local;
use Time::HiRes qw ( time );
use FindBin;
use lib "$FindBin::RealBin/../LML_specs";
use lib "$FindBin::RealBin/../lib";
use LML_specs;
use LML_da_util;
sub new {
my $self = {};
my $proto = shift;
my $class = ref($proto) || $proto;
my $verbose = shift;
my $timings = shift;
printf("\t LML_gen_table: new %s\n",ref($proto)) if($debug>=3);
$self->{VERBOSE} = $verbose;
$self->{TIMINGS} = $timings;
$self->{LMLFH} = undef;
$self->{LAYOUT} = undef;
$self->{IDLISTREF} = undef;
bless $self, $class;
return $self;
}
#
# returns a list of LML object ids which have to included in the objects
# and information tag of the resulting LML file
#
sub get_ids {
my($self) = shift;
return($self->{IDLISTREF});
}
#
# processes the raw LML file data and extracts objects according to the
# requested pattern and generates from this a table structure
#
# Parameters:
#
# filehandler_LML: handler to raw LML file
#
sub process {
my($self) = shift;
my $layoutref = shift;
my $filehandler_LML = shift;
my ($numids,$gid,$contenttype,$idlistref,$objtype_pattern,$patternsref,$selectsref);
$numids=0;
$self->{LAYOUT} = $layoutref;
$self->{LMLFH} = $filehandler_LML;
$gid=$layoutref->{gid};
$contenttype="jobs";#Default content type
if( exists($layoutref->{contenthint}) ){
$contenttype = $layoutref->{contenthint};
}
if(!$contenttype) {
print "LML_gen_table: ERROR no contenttype given for table $gid, skipping ...\n";
return(-1);
}
# check content type
if(lc($contenttype) eq "jobs") {
$objtype_pattern="job";
} elsif(lc($contenttype) eq "nodes") {
$objtype_pattern="node";
} else {
# contenttype is used directly to check objecttype
$objtype_pattern="$contenttype";
}
$self->{OBJTYPE_PATTERN}=$objtype_pattern;
# check pattern
$patternsref=$self->_extract_patterns($layoutref);
# check select
$selectsref=$self->_extract_selects($layoutref);
$idlistref=[];
print "LML_gen_table::process: gid=$gid contenttype=$contenttype objtype_pattern=$objtype_pattern\n"
if($self->{VERBOSE});
$idlistref=$self->_select_objs($objtype_pattern, $patternsref, $selectsref);
$self->{IDLISTREF}=$idlistref;
$numids=scalar @{$idlistref};
# print "LML_gen_table::process: idlist=(",join(',',sort(@{$idlistref})),")\n" if($self->{VERBOSE});
$self->{VALIDATTR}=$self->_update_valid_attributes();
return($numids);
}
sub _extract_patterns {
my($self) = shift;
my($layoutref) = @_;
my(%patterns,$cid,$key,$ptype,$regexp,$ref);
foreach $cid (keys(%{$layoutref->{column}})) {
if(exists($layoutref->{column}->{$cid}->{key})) {
$key=$layoutref->{column}->{$cid}->{key};
} else {
print "LML_gen_table: ERROR, could not find key for column $cid of table $layoutref->{gid}, skipping column ...\n";
next;
}
$patterns{$key}=".*"; # default
if(exists($layoutref->{column}->{$cid}->{pattern})) {
my (@patlist);
foreach $ref (@{$layoutref->{column}->{$cid}->{pattern}}) {
($ptype,$regexp)=@{$ref};
if($ptype eq "include") {
push(@patlist,"$regexp");
}
if($ptype eq "exclude") {
push(@patlist,"($regexp){0}");
}
}
$patterns{$key}="(".join('|',@patlist).")";
}
}
# print "_extract_patterns $layoutref->{gid} -> ",Dumper(\%patterns),"\n";
return(\%patterns);
}
sub _extract_selects {
my($self) = shift;
my($layoutref) = @_;
my(%selects,$cid,$key,$ptype,$rel,$value,$ref);
foreach $cid (keys(%{$layoutref->{column}})) {
if(exists($layoutref->{column}->{$cid}->{key})) {
$key=$layoutref->{column}->{$cid}->{key};
} else {
print "LML_gen_table: ERROR, could not find key for column $cid of table $layoutref->{gid}, skipping column ...\n";
next;
}
$selects{$key}=undef; # default
if(exists($layoutref->{column}->{$cid}->{pattern})) {
my (@selectlist);
foreach $ref (@{$layoutref->{column}->{$cid}->{pattern}}) {
if($ref->[0] eq "select") {
($ptype,$rel,$value)=@{$ref};
$rel=&LML_da_util::unescape_special_characters($rel);
push(@selectlist,[$rel,$value]);
}
}
if($#selectlist>=0) {
$selects{$key}=[@selectlist];
}
}
}
return(\%selects);
}
sub _select_objs {
my($self) = shift;
my($objtype_pattern,$patternsref,$selectsref)=@_;
my (@idlist,$key,$ref,$sref,$skey,$found,$regexp,$selects,$sort,$specref);
keys(%{$self->{LMLFH}->{DATA}->{OBJECT}}); # reset iterator
while(($key,$ref)=each(%{$self->{LMLFH}->{DATA}->{OBJECT}})) {
$found=1;
# check against contenttype
next if($ref->{type} ne $objtype_pattern);
# checking against include/exclude pattern
foreach $skey (keys(%{$patternsref})) {
$regexp=$patternsref->{$skey};
if(exists($self->{LMLFH}->{DATA}->{INFODATA}->{$key}->{$skey})) {
my $val=$self->{LMLFH}->{DATA}->{INFODATA}->{$key}->{$skey};
if($val!~/$regexp/) {
$found=0; # not matched
# print "not matched for $key $skey $regexp\n";
}
} else {
if($regexp ne ".*") {
$found=0; # attribute not available, but user defined a pattern
}
# print "not found for $key $skey $regexp\n";
}
}
# checking against select pattern
foreach $skey (keys(%{$selectsref})) {
$selects=$selectsref->{$skey};
$specref = $LML_specs::LMLattributes->{$objtype_pattern}->{$skey};
$sort="alpha"; # default
if(defined($specref->[0]) ){
$sort="alpha" if ( ($specref->[0] eq "s") || ($specref->[0] eq "k") );
$sort="numeric" if ( ($specref->[0] eq "d") || ($specref->[0] eq "f") );
$sort="date" if ( ($specref->[0] eq "D") );
}
if(exists($self->{LMLFH}->{DATA}->{INFODATA}->{$key}->{$skey})) {
my $val=$self->{LMLFH}->{DATA}->{INFODATA}->{$key}->{$skey};
if($selects) {
foreach $sref (@{$selects}) {
my($rel,$refval)=(@{$sref});
# equal
$found=0 if ($sort eq "numeric") && ($rel eq "=") && (!($val == $refval));
$found=0 if ($sort eq "alpha") && ($rel eq "=") && (!($val eq $refval));
$found=0 if ($sort eq "date") && ($rel eq "=") && (!($val eq $refval));
# not equal
$found=0 if ($sort eq "numeric") && ($rel eq "!=") && (!($val != $refval));
$found=0 if ($sort eq "alpha") && ($rel eq "!=") && (!($val ne $refval));
$found=0 if ($sort eq "date") && ($rel eq "!=") && (!($val ne $refval));
# less (equal)
$found=0 if ($sort eq "numeric") && ($rel eq "lt") && (!($val < $refval));
$found=0 if ($sort eq "numeric") && ($rel eq "le") && (!($val <= $refval));
$found=0 if ($sort eq "date") && ($rel eq "lt") && (!($val lt $refval));
$found=0 if ($sort eq "date") && ($rel eq "le") && (!($val le $refval));
# greater (equal)
$found=0 if ($sort eq "numeric") && ($rel eq "gt") && (!($val > $refval));
$found=0 if ($sort eq "numeric") && ($rel eq "ge") && (!($val >= $refval));
$found=0 if ($sort eq "date") && ($rel eq "gt") && (!($val gt $refval));
$found=0 if ($sort eq "date") && ($rel eq "ge") && (!($val ge $refval));
# (not) match reqexp
$found=0 if ($sort eq "alpha") && ($rel eq "=~") && (!($val=~/$refval/));
$found=0 if ($sort eq "alpha") && ($rel eq "!~") && (!($val!~/$refval/));
}
}
} else {
if($selects) {
$found=0; # attribute not available, but user defined a select
}
# print "skey not defined not found for $key $skey (select)\n";
}
}
if($found) {
push(@idlist,$key);
}
}
return(\@idlist);
}
sub _update_valid_attributes {
my($self) = shift;
my ($key,$k,%validattr,@validattr);
foreach $key (@{$self->{IDLISTREF}}) {
foreach $k (keys %{$self->{LMLFH}->{DATA}->{INFODATA}->{$key}}) {
$validattr{$k}++;
}
}
@validattr=(sort keys(%validattr));
return(\@validattr);
}
sub get_lml_table {
my($self) = shift;
my($ds,$rc,$id,$cid);
my $layoutref = $self->{LAYOUT};
my $tableref = $self->{TABLE};
my(%keylist,$key,$value,$ref, $objtype_pattern, $specref, $active, $lastcid);
$objtype_pattern=$self->{OBJTYPE_PATTERN};
# top level attributes of table
$ds->{id} = $layoutref->{gid};
$ds->{title} = $layoutref->{gid};
$ds->{contenttype}= $tableref->{contenttype};
if(!defined($ds->{contenttype})){
$ds->{contenttype} = $layoutref->{contenthint};
}
$ds->{description}= $tableref->{description} if(exists($tableref->{description}));
# define columns
foreach $cid (sort {$a <=> $b} (keys(%{$layoutref->{column}}))) {
$key = $layoutref->{column}->{$cid}->{key};
$active = $layoutref->{column}->{$cid}->{active};
$specref = $LML_specs::LMLattributes->{$objtype_pattern}->{$key};
if(!$specref) {
print STDERR "unknown table column requested $key, data may be corrupted ...";
$specref = ["s", "O", undef, "unknown column"];
}
next if ( ($active eq "false") and ($specref->[1] ne "M") );
$ds->{column}->{$cid}->{name} = $layoutref->{column}->{$cid}->{key};
$ds->{column}->{$cid}->{id} = $cid;
$ds->{column}->{$cid}->{description} = $specref->[3];
$ds->{column}->{$cid}->{type} = "mandatory" if($specref->[1] eq "M");
$ds->{column}->{$cid}->{type} = "optional" if($specref->[1] ne "M");
$ds->{column}->{$cid}->{sort} = "alpha" if($specref->[0] eq "s");
$ds->{column}->{$cid}->{sort} = "alpha" if($specref->[0] eq "k");
$ds->{column}->{$cid}->{sort} = "date" if($specref->[0] eq "D");
$ds->{column}->{$cid}->{sort} = "numeric" if($specref->[0] eq "d");
$ds->{column}->{$cid}->{sort} = "numeric" if($specref->[0] eq "f");
if(exists($layoutref->{column}->{$cid})) {
if(exists($layoutref->{column}->{$cid}->{pattern})) {
foreach $ref (@{$layoutref->{column}->{$cid}->{pattern}}) {
push(@{$ds->{column}->{$cid}->{pattern}},$ref);
}
}
}
$keylist{$cid} = $layoutref->{column}->{$cid}->{key};
#push(@keylist,$layoutref->{column}->{$cid}->{key});
}
# add data to table
foreach $id (@{$self->{IDLISTREF}}) {
$lastcid = 0;
foreach $cid (sort {$a <=> $b} (keys %keylist)) {
$key = $keylist{$cid};
if(exists($self->{LMLFH}->{DATA}->{INFODATA}->{$id}->{$key})) {
$value=$self->{LMLFH}->{DATA}->{INFODATA}->{$id}->{$key};
} else {
$value="?";
}
$ds->{row}->{$id}->{cell}->{$cid}->{value} = $value;
if (($cid - $lastcid) > 1) {
$ds->{row}->{$id}->{cell}->{$cid}->{cid} = $cid;
}
$lastcid = $cid;
}
}
return($ds);
}
sub get_lml_tablelayout {
my($self) = shift;
my($ds,$rc,$id,$cid);
my $layoutref = $self->{LAYOUT};
my($key,$value,%activekeys,$lastcid,$wsum,$wsumweight,$numcolumns);
$ds->{id}=$layoutref->{id};
$ds->{gid}=$layoutref->{gid};
$ds->{contenthint} = $layoutref->{contenthint};
$numcolumns=scalar keys(%{$layoutref->{column}});
if($numcolumns>0) {
# check width
$wsum=0.0;
foreach $cid (sort {$a <=> $b} (keys(%{$layoutref->{column}}))) {
next if($layoutref->{column}->{$cid}->{active} eq "false");
$layoutref->{column}->{$cid}->{width}=1.0 if(!exists($layoutref->{column}->{$cid}->{width}));
$layoutref->{column}->{$cid}->{width}=1.0 if($layoutref->{column}->{$cid}->{width}<=0);
$wsum+=$layoutref->{column}->{$cid}->{width};
}
if($wsum>0) {$wsumweight=1.0/$wsum;}
else {$wsumweight=1.0;}
foreach $cid (sort {$a <=> $b} (keys(%{$layoutref->{column}}))) {
next if($layoutref->{column}->{$cid}->{active} eq "false");
$layoutref->{column}->{$cid}->{width}*=$wsumweight;
}
# generate columns
$lastcid=0;
foreach $cid (sort {$a <=> $b} (keys(%{$layoutref->{column}}))) {
$ds->{column}->{$cid}->{cid}=$cid;
$ds->{column}->{$cid}->{key}=$layoutref->{column}->{$cid}->{key};
$ds->{column}->{$cid}->{pos}=$layoutref->{column}->{$cid}->{pos};
$ds->{column}->{$cid}->{width}=$layoutref->{column}->{$cid}->{width};
$ds->{column}->{$cid}->{active}=$layoutref->{column}->{$cid}->{active};
$ds->{column}->{$cid}->{sorted}=$layoutref->{column}->{$cid}->{sorted} if (exists ($layoutref->{column}->{$cid}->{sorted}));
if(exists($layoutref->{column}->{$cid})) {
if(exists($layoutref->{column}->{$cid}->{pattern})) {
foreach my $ref (@{$layoutref->{column}->{$cid}->{pattern}}) {
push(@{$ds->{column}->{$cid}->{pattern}},$ref);
}
}
}
$lastcid=$cid if($cid>$lastcid);
$activekeys{$ds->{column}->{$cid}->{key}}++;
}
# add alterative columns (as inactive)
foreach $key (@{$self->{VALIDATTR}}) {
next if($activekeys{$key});
$lastcid++;$cid=$lastcid;
$ds->{column}->{$cid}->{cid}=$cid;
$ds->{column}->{$cid}->{pos}=$cid - 1;
$ds->{column}->{$cid}->{key}=$key;
$ds->{column}->{$cid}->{width}="1";
$ds->{column}->{$cid}->{active}="false";
$lastcid=$cid if($cid>$lastcid);
}
}
return($ds);
}
1;