...
There
...
are
...
four
...
ways
...
of
...
creating
...
a
...
BI
...
Component:
...
create
...
a
...
BI
...
Component
...
from
...
scratch,
...
convert
...
an
...
existing
...
class
...
into
...
a
...
BI
...
Component,
...
create
...
a
...
subclass
...
of
...
ComponentBase
...
(org.pentaho.plugin.ComponentBase),
...
or
...
create
...
a
...
subclass
...
of
...
SimpleComponent
...
(org.pentaho.plugin.core.SimpleComponent).
...
To
...
become
...
a
...
BI
...
Component,
...
a
...
Java
...
object
...
must
...
implement
...
the
...
org.pentaho.core.component.IComponent
...
interface.
...
The
...
IComponent
...
interface
...
extends
...
two
...
other
...
interfaces:
...
org.pentaho.core.audit.IAuditable
...
and
...
org.pentaho.util.logging.ILogger.
...
Pentaho
...
provides
...
classes
...
that
...
implement
...
these
...
interfaces.
...
The
...
hierarchy
...
of
...
the
...
Pentaho
...
classes
...
looks
...
like
...
this:
...
org.pentaho.core.system.PentahoBase
...
(implements
...
ILogger
...
and
...
Serializable)
...
   -->
...
org.pentaho.core.system.PentahoMessenger
...
       -->
...
org.pentaho.plugin.ComponentBase
...
(implements
...
IComponent
...
and
...
IAuditable)
...
           -->
...
org.pentaho.plugin.core.SimpleComponent
...
               -->
...
other
...
Pentaho-provided
...
BI
...
Components
...
You
...
can
...
create
...
your
...
BI
...
Components
...
in
...
whatever
...
package
...
you
...
like
...
whether
...
they
...
are
...
subclasses
...
of
...
Pentaho
...
classes
...
or
...
not.
...
There
...
are
...
no
...
required
...
methods
...
that
...
will
...
be
...
inaccessible
...
if
...
you
...
use
...
a
...
non-Pentaho
...
package.
...
Extend SimpleComponent
This is the easiest way to create a new component and the recommended place to start.
- Create a new Java class that is a subclass of (extends) org.pentaho.plugin.core.SimpleComponent.
...
- Implement
...
- an
...
- executeAction()
...
- method
...
- and
...
- a
...
- getLogger()
...
- method.
...
- See
...
- 'Component
...
- Methods'
...
- below
...
- for
...
- a
...
- description
...
- of
...
- these
...
- methods.
...
Extend ComponentBase
If your component needs to validate its inputs and/or
...
system
...
settings
...
or
...
needs
...
to
...
perform
...
any
...
initialization
...
and/or
...
cleanup,
...
you
...
should
...
extend
...
org.pentaho.plugin.ComponentBase.
...
- Create
...
- a
...
- new
...
- Java
...
- class
...
- that
...
- is
...
- a
...
- subclass
...
- of
...
- (extends)
...
- org.pentaho.plugin.ComponentBase.
...
- Add
...
- code
...
- to
...
- the
...
- init(),
...
- validateSystemSettings(),
...
- validateAction(),
...
- executeAction(),
...
- done(),
...
- and
...
- getLogger()
...
- methods
...
- as
...
- appropriate.
...
- See
...
- 'Component
...
- Methods'
...
- below
...
- for
...
- a
...
- description
...
- of
...
- these
...
- methods.
...
Convert
...
a
...
Java
...
Object
...
into
...
a
...
BI
...
Component
...
If
...
you
...
have
...
an
...
existing
...
object
...
that
...
you
...
wish
...
to
...
convert
...
into
...
a
...
BI
...
Component
...
there
...
are
...
two
...
options.
...
Create
...
a
...
new
...
object
...
that
...
subclasses
...
your
...
existing
...
object
...
and
...
implements
...
the
...
required
...
interfaces
...
Change
...
your
...
object
...
to
...
implement
...
the
...
required
...
interfaces
...
Which
...
of
...
these
...
options
...
is
...
the
...
best
...
for
...
your
...
particular
...
object
...
will
...
depend
...
on
...
your
...
specific
...
circumstances;
...
but,
...
we
...
recommend
...
creating
...
a
...
subclass
...
if
...
only
...
to
...
keep
...
your
...
source
...
file
...
size
...
manageable.
...
If
...
you
...
do
...
need
...
to
...
use
...
this
...
approach
...
most
...
of
...
the
...
code
...
you
...
need
...
to
...
create
...
your
...
new
...
class
...
can
...
be
...
found
...
in
...
these
...
classes:
...
org.pentaho.core.system.PentahoBase,
...
org.pentaho.core.system.PentahoMessenger,
...
and
...
org.pentaho.plugin.ComponentBase.
...
To
...
make
...
this
...
process
...
easier
...
we
...
have
...
created
...
a
...
class,
...
org.pentaho.plugin.ComponentSubclassExample,
...
that
...
contains
...
the
...
code
...
you
...
need.
...
To
...
convert
...
a
...
Java
...
class
...
to
...
a
...
BI
...
Component:
...
- Copy
...
- the
...
- imports,
...
- member
...
- variables,
...
- and
...
- methods
...
- from
...
- org.pentaho.plugin.ComponentSubclassExample
...
- into
...
- your
...
- Java
...
- class.
...
- Add
...
- code
...
- to
...
- the
...
- init(),
...
- validateSystemSettings(),
...
- validateAction(),
...
- executeAction(),
...
- done(),
...
- and
...
- getLogger()
...
- methods
...
- as
...
- appropriate.
...
- See
...
- 'Component
...
- Methods'
...
- below
...
- for
...
- a
...
- description
...
- of
...
- these
...
- methods.
...
Components from Scratch
In order to create a component from scratch a new class that implements the interface org.pentaho.core.component.IComponent
...
must
...
be
...
created.
...
To
...
implement
...
all
...
three
...
interfaces
...
requires
...
about
...
30
...
methods
...
to
...
be
...
implemented.
...
It
...
is
...
not
...
recommended
...
to
...
use
...
this
...
option
...
and
...
there
...
should
...
be
...
no
...
need
...
to
...
do
...
this
...
given
...
the
...
options
...
above.
...
Component Methods
If using one of the three recommended methods for creating new components, the methods below are the BI Component methods that need to be customized to provide your needed functionality. The methods are listed in the order that they are typically called during normal processing. Depending on the option used to create your component, not all of these methods are required. See above sections for more details.
getLogger()
This method creates a Log object that will be use to log messages from your component. It has to be created by your component (instead of a superclass) so that the log correctly records the class name of your object.
This method is implemented with a single line.
Code Block |
---|
public Log getLogger() { return LogFactory.getLog(this.class); } h3. |
validateSystemSettings()
...
This
...
method
...
allows
...
your
...
component
...
to
...
verify
...
that
...
any
...
its
...
required
...
system
...
settings
...
it
...
needs
...
in
...
order
...
to
...
operate
...
are
...
set
...
correctly.
...
For
...
examples,
...
the
...
Kettle
...
component
...
(org.pentaho.plugin.kettle.KettleComponent)
...
checks
...
it
...
system
...
settings
...
to
...
see
...
if
...
it
...
is
...
configured
...
for
...
a
...
file-based
...
or
...
RBDMS-based
...
repository,
...
and
...
the
...
...
component
...
(org.pentaho.plugin.email.EmailComponent)
...
uses
...
its
...
system
...
settings
...
to
...
connect
...
to
...
your
...
...
server.
...
System-wide
...
settings
...
for
...
components
...
should
...
be
...
stored
...
in
...
XML
...
documents
...
in
...
the
...
'system'
...
folder
...
in
...
the
...
Pentaho
...
solution
...
root
...
folder.
...
System
...
settings
...
are
...
ones
...
that
...
will
...
be
...
the
...
same
...
for
...
every
...
instance
...
of
...
your
...
component
...
and
...
that
...
won't
...
change
...
while
...
the
...
server
...
or
...
application
...
is
...
running
...
(unless
...
manually
...
changed
...
by
...
an
...
administrator).
...
In
...
the
...
system
...
folder
...
you
...
will
...
see
...
subdirectories
...
such
...
as
...
'kettle',
...
'quartz',
...
and
...
'smtp-email'.
...
If
...
your
...
component
...
needs
...
system
...
settings
...
you
...
can
...
create
...
a
...
directory
...
to
...
store
...
your
...
settings
...
in
...
and
...
place
...
an
...
XML
...
file
...
in
...
the
...
directory.
...
The
...
XML
...
file
...
can
...
be
...
named
...
anything
...
that
...
you
...
like.
...
Within
...
the
...
XML
...
document
...
you
...
can
...
arrange
...
the
...
settings
...
in
...
any
...
format
...
that
...
you
...
like.
...
The
...
settings
...
file
...
for
...
the
...
...
component
...
provides
...
a
...
good
...
example
...
of
...
a
...
settings
...
file.
...
Within
...
the
...
root
...
solution
...
folder
...
the
...
path
...
to
...
the
...
...
settings
...
file
...
is
...
'system/smtp-email/email_config.xml'.
...
Code Block | ||||
---|---|---|---|---|
| ||||
<email-smtp> <\!-\- The values within <properties> are passed directly to the JavaMail API. For a list of valid properties see http://java.sun.com/products/javamail/javadocs/index.html \--> <properties> <\!-\ <!-- This is the address of your SMTP email server for sending email. e.g. smtp.pentaho.org \--> . smtp.pentaho.org --> <mail.smtp.host></mail.smtp.host> <\!-\ <!-- This is the port of your SMTP email server. Usually this is 25. For GMail this is 587 \--> <mail.smtp.port>25</mail.smtp.port> <\!-\ <!-- The transport for accessing the email server. Usually this is smtp. For GMail this is smtps \--> <mail.transport.protocol>smtp</mail.transport.protocol> <\!-\ <!-- Usually this is 'false'. For GMail it is 'true' \--> <mail.smtp.starttls.enable>false</mail.smtp.starttls.enable> <\!-\ <!-- Set to true if the email server requires the sender to authenticate \--> <mail.smtp.auth>true</mail.smtp.auth> <\!-\ <!-- This is true if the email server requires an SSL connection. Usually 'false'. For GMail this is 'true' \--> <mail.smtp.ssl>false</mail.smtp.ssl> <\!-\- Output debug information from the JavaMail API \--> <mail.debug>false</mail.debug> </properties> <\!-\- This is the default 'from' address that emails from the Pentaho BI Suite Suite will appear to come from e.g. joe.pentaho@pentaho.org \--> <mail.from.default>joe.pentaho@pentaho.org</mail.from.default> <\!-\- This is the user id used to connect to the email server for sending email It is only required if email-authenticate is set to true This is never sent or shown to anyone \--> <mail.userid></mail.userid> <\!-\- This is the password used to connect to the email server for sending email It is only required if email-authenticate is set to true authenticate is set to true This is never sent or shown to anyone \--> <mail.password></mail.password> </email-smtp> |
The
...
...
component
...
accesses
...
these
...
settings
...
by
...
calling
...
PentahoSystem.getSystemSetting().
...
For
...
example:
...
String
...
mailhost
...
=
...
PentahoSystem.getSystemSetting("smtp-email/email_config.xml",
...
"mail.smtp.host",
...
null);
...
The
...
getSystemSetting()
...
method
...
finds
...
an
...
entry
...
in
...
a
...
system
...
setting
...
file
...
and
...
returns
...
it
...
to
...
the
...
component.
...
The
...
component
...
does
...
not
...
need
...
to
...
know
...
where
...
the
...
system
...
settings
...
files
...
are
...
located.
...
See
...
the
...
'Utility'
...
section
...
below
...
for
...
more
...
information
...
on
...
the
...
method
...
PentahoSystem.getSystemSetting().
...
validateAction()
...
This
...
method
...
is
...
called
...
to
...
give
...
your
...
component
...
the
...
chance
...
to
...
verify
...
that
...
it
...
has
...
the
...
inputs
...
and
...
resources
...
that
...
it
...
needs
...
to
...
complete
...
successfully.
...
If
...
you
...
return
...
'false'
...
from
...
this
...
method
...
execution
...
of
...
the
...
action
...
sequence
...
will
...
terminate.
...
This
...
method
...
should
...
only
...
be
...
used
...
to
...
check
...
that
...
the
...
inputs
...
are
...
available
...
it
...
should
...
not
...
check
...
the
...
values
...
of
...
inputs
...
because
...
they
...
are
...
not
...
guaranteed
...
to
...
be
...
available
...
at
...
this
...
point
...
during
...
execution.
...
If
...
your
...
component
...
needs
...
resources
...
such
...
as
...
a
...
template
...
file
...
referred
...
to
...
in
...
the
...
action
...
sequence
...
as
...
"new-employee-greeting",
...
you
...
can
...
check
...
that
...
the
...
resource
...
is
...
available
...
by
...
calling
...
isDefinedResource("new-employee-greeting").
...
If
...
your
...
component
...
needs
...
an
...
input
...
called
...
'employee-id',
...
you
...
can
...
check
...
that
...
it
...
has
...
been
...
defined
...
in
...
the
...
action
...
sequence
...
by
...
calling
...
isDefinedInput("employee-id").
...
If
...
your
...
component
...
needs
...
an
...
output
...
called
...
"employee-greeting-email-text",
...
you
...
can
...
check
...
that
...
it
...
has
...
been
...
defined
...
in
...
the
...
action
...
sequence
...
by
...
calling
...
isDefinedOutput("employee-greeting-email-text").
...
Your
...
validateAction()
...
method
...
would
...
now
...
look
...
like
...
this
Code Block |
---|
public boolean validateAction() { if (\!isDefinedResource("new-employee-greeting")) { error( "A template called 'new-employee-greeting' has not been defined" ); return false; } if (\!isDefinedInput("employee-id")) { { error( "An employee id is needed" ); return false; } if (\!isDefinedOutput("employee-greeting-email-text") ) { { error("An output called 'employee-greeting-email-text' has not been defined" ); return false; } } return true; } |
Notice
...
that
...
we
...
are
...
only
...
checking
...
to
...
see
...
if
...
the
...
input
...
has
...
been
...
defined
...
and
...
we
...
are
...
not
...
trying
...
to
...
get
...
the
...
input
...
value.
...
The
...
validateAction()
...
of
...
the
...
EmailComponent
...
looks
...
like
...
this:
Code Block |
---|
public boolean validateAction() { // make sure that we can get a 'to' email address if (\!isDefinedInput("to")) { error(Messages.getErrorString("Email.ERROR_0001_TO_NOT_DEFINED", getActionName())); getActionName())); return false; } // make sure that we can get a subject for the email if (\!isDefinedInput("subject")) { error(Messages.getErrorString("Email.ERROR_0002_SUBJECT_NOT_DEFINED", getActionName())); return false; } // make sure that we have either a plain text or html message for the email if (\!isDefinedInput("message-plain") && \!isDefinedInput("message-html")) { error(Messages.getErrorString("Email.ERROR_0003_BODY_NOT_DEFINED", ", getActionName())); return false; } return true; } |
Notice
...
that
...
this
...
method
...
does
...
not
...
check
...
for
...
the
...
optional
...
parameters
...
such
...
as
...
'cc',
...
'bcc',
...
or
...
...
attachments
...
but
...
only
...
checks
...
for
...
the
...
minimum
...
parameters
...
that
...
are
...
required
...
for
...
the
...
component
...
to
...
execute
...
successfully.
...
You
...
do
...
not
...
have
...
to
...
call
...
for
...
each
...
individual
...
resource,
...
input,
...
or
...
output.
...
If
...
you
...
prefer,
...
you
...
can
...
work
...
with
...
java.util.Set
...
objects
...
that
...
contain
...
the
...
names
...
of
...
the
...
available
...
items.
...
These
...
sets
...
can
...
be
...
obtained
...
by
...
calling
...
getResourceNames(),
...
getInputNames(),
...
and
...
getOutputNames().
...
For
...
example
Code Block |
---|
Set inputNames = getInputNames(); if( \!inputNames.contains( "param1" ) && \!inputNames.contains( "param2" ) ) { error( "I need both param1 and param2" ); return false; } h3. |
init()
...
This
...
method
...
is
...
called
...
to
...
allow
...
the
...
component
...
to
...
perform
...
any
...
initialization
...
operations
...
that
...
are
...
required
...
before
...
the
...
executeAction()
...
is
...
called.
...
executeAction()
...
This
...
method
...
is
...
called
...
to
...
cause
...
the
...
component
...
to
...
perform
...
its
...
function.
...
Within
...
this
...
method
...
you
...
can
...
call
...
other
...
internal
...
API
...
methods
...
to
...
get
...
the
...
values
...
of
...
inputs,
...
to
...
get
...
resources,
...
to
...
ask
...
users
...
for
...
parameters,
...
and
...
to
...
get
...
output
...
streams.
...
Typically,
...
during
...
the
...
execute
...
method
...
a
...
component
...
will:
...
- Gather
...
- input
...
- values.
...
- These
...
- might
...
- be
...
- parameters
...
- or
...
- component
...
- settings.
...
- If
...
- the
...
- input
...
- values
...
- are
...
- not
...
- complete,
...
- the
...
- component
...
- can
...
- stop
...
- executing
...
- or
...
- prompt
...
- the
...
- user
...
- for
...
- additional
...
- information.
...
- Gather
...
- resources.
...
- These
...
- might
...
- be
...
- templates
...
- or
...
- definition
...
- files.
...
- Get
...
- an
...
- output
...
- pipe
...
- of
...
- some
...
- kind
...
- (e.g.
...
- an
...
- output
...
- stream).
...
- Create
...
- output
...
- contents.
...
- Return
...
- the
...
- status
...
- of
...
- the
...
- execution.
...
See
...
'Internal
...
API'
...
below
...
for
...
descriptions
...
of
...
the
...
methods
...
available
...
for
...
the
...
component
...
to
...
use.
...
We
...
will
...
use
...
the
...
executeAction()
...
of
...
the
...
PrintComponent
...
(org.pentaho.plugin.print.PrintComponent)
...
as
...
an
...
example
...
(minor
...
modifications
...
have
...
been
...
made
...
for
...
clarity).
...
Code Block |
---|
protected boolean executeAction() { String printFileName = null; IActionResource printFileResource = null; // see if we are printing a file if (isDefinedInput("print-file")) { // get the name of the file to print printFileName = getInputStringValue("print-file"); } InputStream inStream = null; // Get the name of the printer to use if (isDefinedInput("printer-name")) { printerName = getInputStringValue("printer-name"); } // try to find the requested printer PrintService printer = getPrinterInternal(printerName); if (printer == null) { // the requested printer is not available if (\!feedbackAllowed()) { // we are not allowed to prompt the user for a printer, we have to fail error( "The requested printer "+printerName+" is not available" ); is not available" ); return false; } } // prompt the user for an available printer // get a list of available print services PrintService\[\ PrintService[] services = PrinterJob.lookupPrintServices(); PrinterJob.lookupPrintServices(); ArrayList values = new ArrayList(); // add each print service to our list of printers for (int i = 0; i < services.length; i++) { String value = services\[i\].getName(); services[i].getName(); values.add(value); } } // create a parameter for the user to select from createFeedbackParameter("printer-name", "select a printer", "", null, values, null, "select"); return null; } return null; } promptNeeded(); return true; } } // Get the number of copies int copies = 1; if (isDefinedInput("copies")) { copies = Integer.valueOf(getInputStringValue("copies")).intValue(); } // Check for a valid printFileName or printFile Resource if (printFileName \!= null) { try { inStream = new FileInputStream(printFileName); } catch (FileNotFoundException fnfe) { error(fnfe.toString(), fnfe); return false; } } // Set the input source for sending to the driver. InputSource source = new InputSource(inStream); try { Driver driver = new Driver(source, null); PrinterJob pj = PrinterJob.getPrinterJob(); pj.setPrintService(printer); .getPrinterJob(); pj.setPrintService(printer); PrintRenderer renderer = new PrintRenderer(pj, copies); driver.setRenderer(renderer); driver.run(); } catch (Exception ex) { error( "Could not print the document", ex); return false; } return false; } return true; } h3.} |
done()
...
This
...
method
...
is
...
called
...
to
...
give
...
the
...
component
...
the
...
opportunity
...
to
...
perform
...
any
...
cleanup
...
operations
...
that
...
are
...
necessary.