You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Nicola Ken Barozzi <ni...@apache.org> on 2002/06/04 22:18:50 UTC

[Morphos] Java data morphing package

*CROSSPOST * PROPOSAL OF PARTICIPATION *

Welcome to the first public discussion about project Morphos.

This message is being posted to many lists because it has the aim of solving
a common need.

The discussion will continue, for those interested, on the jakarta commons
mailing list.
To subscribe, send an empty mail to
commons-dev-subscribe@jakarta.apache.org


What is Morphos?
-----------------------------
Morphos will be a Java Api and implementation for transforming data, in any
form it may be: xml, streams, objects.

It focuses on the API and framework, and demands implementation to other
projects-modules wherever possible.


Why Morphos?
-----------------------------
Morphos starts from a need around a community of developers, with an initial
charter committed in Jakarta Commons Sandbox.
Before anything got committed, it has slightly evolved from being tied
initially to XML.
Here is the old charter
(http://cvs.apache.org/viewcvs/jakarta-commons-sandbox/morphos/PROPOSAL.txt?
rev=HEAD&content-type=text/vnd.viewcvs-markup).

This mail illustrates the latest status of the private discussions, and a is
the start of the public one.

Currently there are many projects that need or would benefit from a generic
transformation API:

  - Jakarta POI -

      OLE<->XML transformations

  - Cocoon -

        using a single api and a contrib section for the
        loads of components it now hosts in the core

  - FOP -

        redesigning the main interface for FO<->PDF,MIF,...etc

   - Krysalis Wings -

         transforming chart XML format to SVG or image formats

Other projects that can be wrapped round this api are numerous:
  - Batik (image transcoders)
  - Xerces-Xalan
  - Avalon Excalibur Converter
  - Commons Digester
  - Jakarta-commons-sandbox Jelly
  -  etc...

A componentization of the transformation process can help reuse and minimize
code duplication.


What does it do?
-----------------------------
 Morphos should simply do:

 data  --> morphos ---> data

 Data can be:
   - stream
   - events
   - objects

I don't see other basic generic "data" types, since files and such can
become streams and viceversa without any format or form conversion.
I want a *very* simple api, with no duplicated methods.
IE having get(Stream) and get(File) is not necessary IMO, since they do the
same thing.
The main API must be very simple. We can always add helper classes.

 I took look at these APIs:
 - Jaxp
 - Batik Transcoder

Jaxp:
Baised towards xml (more in package names than in fact). Already has a bad
track on version using (the infamious "endorsed" dir and param). Uses static
method for getting the transformer.

Batik Transcoder:
Good API but it's source can contain a Reader, InputStream, Contenthandler,
etc, so it's tied to these.
No support for pipelining of transcodes.

Ok, but in Concrete?
------------------------------

Here is the proposed API, all in package org.apache.commons.morphos:

/**
 * The interface that is implemented by classes that morph.
 * It uses two params and not a return value to make it usable with
 * event based Objects (contenthandlers).
 * Parameters are key pairs, used to configure the Morpher.
 * Events in the Morpher are notified by registering a listener.
 */
public interface Morpher {

    void morph(Object input, Object output) throws MorphException.
IOException;

    void addParameter(String paramName, String paramValue);
    String getParameter(String paramName);
    void remove Parameter(String paramName);
    String[] getParameterNames();
    String[] getParameterValues();

    void addNotificationListener(NotificationListener nl);
    void removeNotificationListener(NotificationListener nl);
    void clearNotificationListeners();

}

/**
 * A Morpher made out of a sequence of morphers.
 */

public interface MorpherPipeline extends Morpher {

    void addStage(Morpher nextMorpher);

}



/**
 * The Factory for Morphers.
 * There is a getDefaultFactory method for easy use.
 * Used in frameworks it's better not to use it and rely on
 * services that give the proper MorpherFactory.
 */
public abstract MorpherFactory  {

    Morpher getMorpher(DataType inputType, DataType outputType);
    Morpher getMorpher(name);

    Morpher getPreparedMorpher(DataType inputType, DataType outputType);
    Morpher getPreparedMorpher(name);

    static MorpherFactory getDefaultFactory();
}


/**
 * Describes what the format of the data is.
 * It consists of a mimetype (format) and a dataForm (representation).
 * For example a gif image file and a jped image file have a different
mimetype but same dataform (file).
 * An SVG file and an SVG DOM in memory have same mimetype but different
dataform.
 */
public interface DataType {

    void setMimeType(String mimetype);
    void setDataForm(String format);

    String getMimeType();
    String getDataForm();

}


--
Nicola Ken Barozzi                   nicolaken@apache.org
            - verba volant, scripta manent -
   (discussions get forgotten, just code remains)
---------------------------------------------------------------------



---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org


Re: [Morphos] Java data morphing package

Posted by Jeremias Maerki <je...@outline.ch>.
Sounds interesting to me, and it comes at the right time. What do you
others say to this?

Cheers,
Jeremias Märki

mailto:jeremias.maerki@outline.ch

OUTLINE AG
Postfach 3954 - Rhynauerstr. 15 - CH-6002 Luzern
Tel. +41 41 317 2020 - Fax +41 41 317 2029
Internet http://www.outline.ch


---------------------------------------------------------------------
To unsubscribe, e-mail: fop-dev-unsubscribe@xml.apache.org
For additional commands, email: fop-dev-help@xml.apache.org


Re: [Morphos] Java data morphing package - second stab

Posted by Nicola Ken Barozzi <ni...@apache.org>.
From: "Stephen Colebourne" <sc...@eurobell.co.uk>

> >   * It uses two params and not a return value to make it usable with
> >   * event based Objects (contenthandlers).
> >   * Events in the Morpher are notified by registering a listener.
> >   * [new] parameters are managed with beans get/set methods
> >   *            *none* are mandatory
> >   */
> >  public interface Morpher {
> >      void morph(Object input, Object output) throws MorphException.
> > [Clarification]
> > Why not
> >   Object morph(Object input) throws MorphException, IOException;
> > ?
> > Because if the output object is a SAX handler, the morphing doesn't take
> > place, and this is not evident.
> > Any other pros-cons?
>
> The problem with the two object input approach is that it precludes a
simple
> type convertor being written using this architecture. A type convertor
> typically takes in an immutable object and returns an imutable object
> (String/Integer etc.)

Hmmm...

Integer input = new Integer(1);
String output = null;
[...]
mymorpher.morph(input , output);

If the morpher does

  output=input.toString();

wouldn't it work?

> Object morph(Object input)   does allow a String to Integer convertor, but
> is obviously a second interface, potentially providing confusion.

Yes, we need a single way, I agree.

> Given this, you may want to refine the definition of what can or can't be
> morphed (ie. to exclude immutable outputs).

Thinking of the immutable objects, what is more confusing:

Integer input = new Integer(1);
String output = "immutable string that will be replaced";
[...]
mymorpher.morph(input , output);

or

Contenthandler input = ...
Contenthandler output = ...
output = mymorpher.morph(input);

and still need to trigger the morphing?


IMO you are right, immutable objects make the morph(input, output) method a
bit ridiculous.

I think you've convinced me, what do others think?

--
Nicola Ken Barozzi                   nicolaken@apache.org
            - verba volant, scripta manent -
   (discussions get forgotten, just code remains)
---------------------------------------------------------------------


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: [Morphos] Java data morphing package - second stab

Posted by Stephen Colebourne <sc...@eurobell.co.uk>.
>   * It uses two params and not a return value to make it usable with
>   * event based Objects (contenthandlers).
>   * Events in the Morpher are notified by registering a listener.
>   * [new] parameters are managed with beans get/set methods
>   *            *none* are mandatory
>   */
>  public interface Morpher {
>      void morph(Object input, Object output) throws MorphException.
> [Clarification]
> Why not
>   Object morph(Object input) throws MorphException, IOException;
> ?
> Because if the output object is a SAX handler, the morphing doesn't take
> place, and this is not evident.
> Any other pros-cons?

The problem with the two object input approach is that it precludes a simple
type convertor being written using this architecture. A type convertor
typically takes in an immutable object and returns an imutable object
(String/Integer etc.)

Object morph(Object input)   does allow a String to Integer convertor, but
is obviously a second interface, potentially providing confusion.

Given this, you may want to refine the definition of what can or can't be
morphed (ie. to exclude immutable outputs).

Stephen


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


[Morphos] Java data morphing package - second stab

Posted by Nicola Ken Barozzi <ni...@apache.org>.
Ok, here is the second stab at it :-)
I'm still crossposting now to other projects that have shown interest.

I have gotten many suggestions privately, so this will contain them +
clarifications, and a concrete example.

This discussion properly resides on the Jakarta Commons mailing list.
To subscribe, send an empty mail to commons-dev-subscribe@jakarta.apache.org

From: "Nicola Ken Barozzi" <ni...@apache.org>

> What is Morphos?
> -----------------------------
> Morphos will be a Java Api and implementation for transforming data, in
any
> form it may be: xml, streams, objects.
>
> It focuses on the API and framework, and demands implementation to other
> projects-modules wherever possible.
>
>
> Why Morphos?
> -----------------------------
> Morphos starts from a need around a community of developers, with an
initial
> charter committed in Jakarta Commons Sandbox.

[...]

> What does it do?
> -----------------------------
>  Morphos should simply do:
>
>  data  --> morphos ---> data
>
>  Data can be:
>    - stream
>    - events
>    - objects
>
> I don't see other basic generic "data" types, since files and such can
> become streams and viceversa without any format or form conversion.
> I want a *very* simple api, with no duplicated methods.
> IE having get(Stream) and get(File) is not necessary IMO, since they do
the
> same thing.
> The main API must be very simple. We can always add helper classes.

[...]

Ok, but in Concrete?
 ------------------------------
>
> Here is the proposed API, all in package org.apache.commons.morphos:
>
> /**
>  * The interface that is implemented by classes that morph.
>  * It uses two params and not a return value to make it usable with
>  * event based Objects (contenthandlers).
>  * Parameters are key pairs, used to configure the Morpher.
>  * Events in the Morpher are notified by registering a listener.
>  */
> public interface Morpher {
>
>     void morph(Object input, Object output) throws MorphException.
> IOException;
>
>     void addParameter(String paramName, String paramValue);
>     String getParameter(String paramName);
>     void remove Parameter(String paramName);
>     String[] getParameterNames();
>     String[] getParameterValues();
>
>     void addNotificationListener(NotificationListener nl);
>     void removeNotificationListener(NotificationListener nl);
>     void clearNotificationListeners();
>
> }

 /**
  * The interface that is implemented by classes that morph.
  * It uses two params and not a return value to make it usable with
  * event based Objects (contenthandlers).
  * Events in the Morpher are notified by registering a listener.
  * [new] parameters are managed with beans get/set methods
  *            *none* are mandatory
  */
 public interface Morpher {

     void morph(Object input, Object output) throws MorphException.
 IOException;

     void addNotificationListener(NotificationListener nl);
     void removeNotificationListener(NotificationListener nl);
     void clearNotificationListeners();

 }

[Clarification]
Why not
  Object morph(Object input) throws MorphException, IOException;
?

Because if the output object is a SAX handler, the morphing doesn't take
place, and this is not evident.
Any other pros-cons?

[Clarification 2]
Why use Object as input and output?
Why not use different types?

Genericity.
See the below comments after the Factory/Manager.

> /**
>  * A Morpher made out of a sequence of morphers.
>  */
>
> public interface MorpherPipeline extends Morpher {
>
>     void addStage(Morpher nextMorpher);
>
> }

This remains.

>
> /**
>  * The Factory for Morphers.
>  * There is a getDefaultFactory method for easy use.
>  * Used in frameworks it's better not to use it and rely on
>  * services that give the proper MorpherFactory.
>  */
> public abstract MorpherFactory  {
>
>     Morpher getMorpher(DataType inputType, DataType outputType);
>     Morpher getMorpher(name);
>
>     Morpher getPreparedMorpher(DataType inputType, DataType outputType);
>     Morpher getPreparedMorpher(name);
>
>     static MorpherFactory getDefaultFactory();
> }

 /**
  * The Morphers' manager.
  * There is a getDefaultFactory method for easy use.
  * Used in frameworks it's better not to use it and rely on
  * services that give the proper MorpherFactory.
  */
 public interface MorpherManager  {

     Morpher getMorpher(DataType inputType, DataType outputType);
     Morpher getMorpher(name);

     Morpher getPreparedMorpher(DataType inputType, DataType outputType);
     Morpher getPreparedMorpher(name);
 }

I've removed the static method, and made it an interface.
It will be the MorpherManager implementation that can use this pattern.

Why not *Factory?
Because it does more than just create them.

[Clarification 2]
Why is a Manager needed?

Because (see clarification 1) any Morpher instance is supposed to be an
implementation that is guaranteed to work with a determined kind of Objects
(a subset); this enforcement is done by the Manager.


> /**
>  * Describes what the format of the data is.
>  * It consists of a mimetype (format) and a dataForm (representation).
>  * For example a gif image file and a jped image file have a different
> mimetype but same dataform (file).
>  * An SVG file and an SVG DOM in memory have same mimetype but different
> dataform.
>  */
> public interface DataType {
>
>     void setMimeType(String mimetype);
>     void setDataForm(String format);
>
>     String getMimeType();
>     String getDataForm();
>
> }

This becomes:
 /**
  * Describes what the format of the data is.
  * It consists of a mimetype (format) and a dataForm (representation).
  * For example a gif image file and a jped image file have a different
 mimetype but same dataform (file).
  * An SVG file and an SVG DOM in memory have same mimetype but different
 dataform.
  */
 public class DataType {

     ....

     public DataType (String mimetype, String format) {
        ...
     }

     public DataType () {
        ...
     }

     void setMimeType(String mimetype){...};
     void setDataForm(String format){...};

     String getMimeType(){...};
     String getDataForm(){...};

 }


[Example]

/* Create the Manager that gives me the morphers */
MorpherManager  mmanager = new SimpleMorpherManager("mmanager-conf.xml");

/* Get a jaxp Morpher by name */
Morpher jaxpmorpher =  mmanager.getMorpher("jaxp");

jaxpmorpher.setStylesheet("transform.xml");

/* Get a Morpher that serializes an XML dom to a stream */
Morpher streammorpher =
  mmanager.getMorpher(
     new DataType("text/xml", "object/dom"),
     new DataType("text/xml", "stream/unix")
   );

Chain the two:

MorpherPipeline mpipeline =  new SimpleMorpherPipeline();
mpipeline.addStage(jaxpmorpher );
mpipeline.addStage(streammorpher );

try{
  mpipeline.morph(myDomObject, outputstream);
}
catch(IMorphException ioe){
 .....}
catch(IOException ioe){
.....}



--
Nicola Ken Barozzi                   nicolaken@apache.org
            - verba volant, scripta manent -
   (discussions get forgotten, just code remains)
---------------------------------------------------------------------


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


[Morphos] Java data morphing package - second stab

Posted by Nicola Ken Barozzi <ni...@apache.org>.
Ok, here is the second stab at it :-)
I'm still crossposting now to other projects that have shown interest.

I have gotten many suggestions privately, so this will contain them +
clarifications, and a concrete example.

This discussion properly resides on the Jakarta Commons mailing list.
To subscribe, send an empty mail to commons-dev-subscribe@jakarta.apache.org

From: "Nicola Ken Barozzi" <ni...@apache.org>

> What is Morphos?
> -----------------------------
> Morphos will be a Java Api and implementation for transforming data, in
any
> form it may be: xml, streams, objects.
>
> It focuses on the API and framework, and demands implementation to other
> projects-modules wherever possible.
>
>
> Why Morphos?
> -----------------------------
> Morphos starts from a need around a community of developers, with an
initial
> charter committed in Jakarta Commons Sandbox.

[...]

> What does it do?
> -----------------------------
>  Morphos should simply do:
>
>  data  --> morphos ---> data
>
>  Data can be:
>    - stream
>    - events
>    - objects
>
> I don't see other basic generic "data" types, since files and such can
> become streams and viceversa without any format or form conversion.
> I want a *very* simple api, with no duplicated methods.
> IE having get(Stream) and get(File) is not necessary IMO, since they do
the
> same thing.
> The main API must be very simple. We can always add helper classes.

[...]

Ok, but in Concrete?
 ------------------------------
>
> Here is the proposed API, all in package org.apache.commons.morphos:
>
> /**
>  * The interface that is implemented by classes that morph.
>  * It uses two params and not a return value to make it usable with
>  * event based Objects (contenthandlers).
>  * Parameters are key pairs, used to configure the Morpher.
>  * Events in the Morpher are notified by registering a listener.
>  */
> public interface Morpher {
>
>     void morph(Object input, Object output) throws MorphException.
> IOException;
>
>     void addParameter(String paramName, String paramValue);
>     String getParameter(String paramName);
>     void remove Parameter(String paramName);
>     String[] getParameterNames();
>     String[] getParameterValues();
>
>     void addNotificationListener(NotificationListener nl);
>     void removeNotificationListener(NotificationListener nl);
>     void clearNotificationListeners();
>
> }

 /**
  * The interface that is implemented by classes that morph.
  * It uses two params and not a return value to make it usable with
  * event based Objects (contenthandlers).
  * Events in the Morpher are notified by registering a listener.
  * [new] parameters are managed with beans get/set methods
  *            *none* are mandatory
  */
 public interface Morpher {

     void morph(Object input, Object output) throws MorphException.
 IOException;

     void addNotificationListener(NotificationListener nl);
     void removeNotificationListener(NotificationListener nl);
     void clearNotificationListeners();

 }

[Clarification]
Why not
  Object morph(Object input) throws MorphException, IOException;
?

Because if the output object is a SAX handler, the morphing doesn't take
place, and this is not evident.
Any other pros-cons?

[Clarification 2]
Why use Object as input and output?
Why not use different types?

Genericity.
See the below comments after the Factory/Manager.

> /**
>  * A Morpher made out of a sequence of morphers.
>  */
>
> public interface MorpherPipeline extends Morpher {
>
>     void addStage(Morpher nextMorpher);
>
> }

This remains.

>
> /**
>  * The Factory for Morphers.
>  * There is a getDefaultFactory method for easy use.
>  * Used in frameworks it's better not to use it and rely on
>  * services that give the proper MorpherFactory.
>  */
> public abstract MorpherFactory  {
>
>     Morpher getMorpher(DataType inputType, DataType outputType);
>     Morpher getMorpher(name);
>
>     Morpher getPreparedMorpher(DataType inputType, DataType outputType);
>     Morpher getPreparedMorpher(name);
>
>     static MorpherFactory getDefaultFactory();
> }

 /**
  * The Morphers' manager.
  * There is a getDefaultFactory method for easy use.
  * Used in frameworks it's better not to use it and rely on
  * services that give the proper MorpherFactory.
  */
 public interface MorpherManager  {

     Morpher getMorpher(DataType inputType, DataType outputType);
     Morpher getMorpher(name);

     Morpher getPreparedMorpher(DataType inputType, DataType outputType);
     Morpher getPreparedMorpher(name);
 }

I've removed the static method, and made it an interface.
It will be the MorpherManager implementation that can use this pattern.

Why not *Factory?
Because it does more than just create them.

[Clarification 2]
Why is a Manager needed?

Because (see clarification 1) any Morpher instance is supposed to be an
implementation that is guaranteed to work with a determined kind of Objects
(a subset); this enforcement is done by the Manager.


> /**
>  * Describes what the format of the data is.
>  * It consists of a mimetype (format) and a dataForm (representation).
>  * For example a gif image file and a jped image file have a different
> mimetype but same dataform (file).
>  * An SVG file and an SVG DOM in memory have same mimetype but different
> dataform.
>  */
> public interface DataType {
>
>     void setMimeType(String mimetype);
>     void setDataForm(String format);
>
>     String getMimeType();
>     String getDataForm();
>
> }

This becomes:
 /**
  * Describes what the format of the data is.
  * It consists of a mimetype (format) and a dataForm (representation).
  * For example a gif image file and a jped image file have a different
 mimetype but same dataform (file).
  * An SVG file and an SVG DOM in memory have same mimetype but different
 dataform.
  */
 public class DataType {

     ....

     public DataType (String mimetype, String format) {
        ...
     }

     public DataType () {
        ...
     }

     void setMimeType(String mimetype){...};
     void setDataForm(String format){...};

     String getMimeType(){...};
     String getDataForm(){...};

 }


[Example]

/* Create the Manager that gives me the morphers */
MorpherManager  mmanager = new SimpleMorpherManager("mmanager-conf.xml");

/* Get a jaxp Morpher by name */
Morpher jaxpmorpher =  mmanager.getMorpher("jaxp");

jaxpmorpher.setStylesheet("transform.xml");

/* Get a Morpher that serializes an XML dom to a stream */
Morpher streammorpher =
  mmanager.getMorpher(
     new DataType("text/xml", "object/dom"),
     new DataType("text/xml", "stream/unix")
   );

Chain the two:

MorpherPipeline mpipeline =  new SimpleMorpherPipeline();
mpipeline.addStage(jaxpmorpher );
mpipeline.addStage(streammorpher );

try{
  mpipeline.morph(myDomObject, outputstream);
}
catch(IMorphException ioe){
 .....}
catch(IOException ioe){
.....}



--
Nicola Ken Barozzi                   nicolaken@apache.org
            - verba volant, scripta manent -
   (discussions get forgotten, just code remains)
---------------------------------------------------------------------


---------------------------------------------------------------------
To unsubscribe, e-mail: fop-dev-unsubscribe@xml.apache.org
For additional commands, email: fop-dev-help@xml.apache.org