xmlgraphics-fop-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michael Rubin <mru...@thunderhead.com>
Subject Re: Event broadcasting and listening question - solved!
Date Tue, 17 May 2011 09:22:30 GMT
Hello again. Thanks again to Jeremias's invaluable help. Much 
appreciated. I believe the issue is now resolved. For the benefit of 
everyone else here is a summary of what I did:

1. Set up the listener, adaptor and producer:
- Added 'void warnRevision3PermissionsIgnored(Object source);' (and its 
javadoc) to PDFEventProducer in the org.apache.fop.render.pdf package 
and added a corresponding entry to the xml.
- Created org.apache.fop.pdf.PDFEventListener interface containing just 
'void warnRevision3PermissionsIgnored(Object source);'.
- Created PDFLibraryEventAdaptor in the org.apache.fop.render.pdf 
package that extends the PDFEventListener.

So the listener gets called from PDFEncryptionJCE.init() which hooks 
into the producer via the adaptor, thereby decoupling FOP's event 
subsystem from the PDF library.

2. Ensure the PDFDocument exists before init time:

PDFEncryptionJCE.make(): Added PDFDocument parameter to the method 
parameters. Call setDocument() to set the PDF before the init() method 
is called. The PDFDocument is passed in from 
PDFEncryptionManager.newInstance(), and comes from 
PDFDocument.setEncryption() (where 'this' is passed in). Compare current 
where the document is set in PDFDocument.setEncryption() after init time.

3. Ensure the listener is set up before init time:

Moved the listener setup code from
PDFDocumentHandler.startDocument() to
PDFRenderingUtil.setupPDFDocument() (just above the setupPDFEncryption 
method call).

Now the PDF Document and its listener are available from within the 
init() method of PDFEncryptionJCE.



On 16/05/11 09:38, Michael Rubin wrote:
> Thanks again Jeremias. Your help much appreciated.
> I have made the PDFEncryptionJCE class pass itself as source into
> PDFEventListener.warnRevision3PermissionsIgnored() which gets passed
> onto the PDFEventProducer.
> Yes I am indeed calling
> PDFEventListener.warnRevision3PermissionsIgnored() from the
> PDFEncryptionJCE class. The call is originating from the init() method.
> A bit of debugging and a fresh mind this morning revealed that
> getDocumentSafely() is throwing an exception as the returned document is
> null. (That was getting swallowed up and the InvocationTargetException
> thrown instead that I got at the end of Friday.) So I think your last
> paragraph is applicable in that PDFEncryptionManager will need to be
> modified to set the PDF immediately as you say. So my next step is to
> work out how I should do that...
> Thanks!
> -Mike
> On 14/05/11 10:42, Jeremias Maerki wrote:
>> On 13.05.2011 17:06:56 Michael Rubin wrote:
>>> Thanks for your reply. I have now added the getter and setter to
>>> PDFDocument as shown below and added 'this.pdfDoc.setEventListener(new
>>> PDFLibraryEventAdapter(getUserAgent().getEventBroadcaster());' to
>>> PDFDocumentHandler.startDocument() (last line inside the try block). Now
>>> I can get the listener from the PDFEncryptionJCE class. However what do
>>> I do with it?
>> You call your PDFEventListener.warnRevision3PermissionsIgnored() method.
>>> And how does this relate to the producer class and the
>>> EventBroadcaster that I am trying to get hold of?
>> It doesn't. That's part of the decoupling. The PDFEncryptionJCE should
>> know nothing of the EventProducer or EventBroadcaster.
>> Maybe the attached UML helps a bit (I don't usually do UML so I'm not
>> sure I've made any mistakes).
>>> In your first reply you said to create the Listener and Producer
>>> interfaces. Based on the FontEvent* classes, both of these had an event
>>> definition for their events. But in the latest reply you are saying not
>>> to put my event in the new PDFEventListener? That would make it an empty
>>> interface then if I understand right. So what would its purpose be? I
>>> can't seem to do anything with it.
>> Sorry for the confusion here. I didn't remember that there was already
>> an EventProducer in org.apache.fop.render.pdf. So adding a new
>> EventProducer doesn't make much sense. Instead your
>> warnRevision3PermissionsIgnored() should be added to the existing one.
>> No new EventProducer is necessary (and I didn't notice that at first).
>>> Following discussion with a colleague (Vincent) I left the listener
>>> method in (but without the source) and made the call to that to kick off
>>> the event. However now I get an InvocationTargetException when I try to
>>> get the PDF Doc in order to invoke the listener event method. Looking at
>>> the stack trace it happens when I call the
>>> PDFDocument.getDocumentSafely() method. It seems when debugging to be
>>> PDFEncryptionManager.newInstance() where the error is occurring, the 3rd
>>> line calling makeMethod.invoke(...). (I attempted to run the build ant
>>> script and then refresh eclipse but this didn't make any difference.)
>> I can't help much with that InvocationTargetException. Maybe if you
>> posted a patch so I could reproduce it....
>>> I will continue with this on Monday. Any further pointers in the
>>> meantime very much appreciated.
>>> There are two questions that come from my colleague:
>>> 1. What is the source object for? And do we need it referenced in the
>>> Listener? Or just the producer?
>> My original idea was that this object gives the event handler a chance
>> to intercept and modify the object that is the event origin. In most
>> cases, it will certainly be ignored but someone might find it handy. And
>> to have it in the producer means you also have to have it in the
>> PDFEventListener. See also java.util.EventObject from which
>> org.apache.fop.events.Event is derived.
>>> 2. Why should we get the PDFDocument object from the Encryption class?
>> It's a PDFObject, right? So it should already have the PDFDocument. That
>> makes access to the PDFEventListener easy.
>>> Should the listener not be passed into the Encryption class via its
>>> constructor rather than having to go fetch the listener?
>> Both are valid ways but since I expect the PDFDocument to already be set,
>> I see no point in giving more information that can otherwise be easily
>> accessed. Well, it could be that your event happens before the
>> PDFDocument is set on that object (see PDFDocument.setEncryption()). In
>> that case PDFEncryptionManager might have to be changed to pass in the
>> PDFDocument immediately. Or you pass in the PDFEventListener, although I
>> find the former more useful and flexible.
>>> Thanks!
>>> -Mike
>>> On 12/05/11 21:29, Jeremias Maerki wrote:
>>>> On 12.05.2011 10:44:41 Michael Rubin wrote:
>>>>> Thanks a lot for your response Jeremias. I have now done the following:
>>>>> - Added 'void warnRevision3PermissionsIgnored(Object source);' (and its
javadoc) to PDFEventProducer in the org.apache.fop.render.pdf package and added a corresponding
entry to the xml. Removed the org.apache.fop.pdf.PDFEventProducer class and xml.
>>>>> - Created org.apache.fop.pdf.PDFEventListener interface containing just
'void warnRevision3PermissionsIgnored(Object source);'.
>>>>> - Created PDFLibraryEventAdaptor in the org.apache.fop.render.pdf package
that extends the PDFEventListener. (Currently just contains my new event. Should I also add
the existing 2 render.pdf events to this class?)
>>>> Or do it the other way around: add your new event to PDFEventProcuder.
>>>> Doesn't make sense to have two.
>>>>>      I can also see how to obtain the PDFDocument object from the
>>>>> PDFEncryptionJCE class via the getDocumentSafely() method. But I am not
sure how to get the event broadcaster from that object. How is this done?
>>>> public class PDFDocument {
>>>> [..]
>>>>        private PDFEventListener listener;
>>>> [..]
>>>>        public void setListener(PDFEventListener listener) {
>>>>            this.listener = listener;
>>>>        }
>>>>        PDFEventListener getListener() {
>>>>            return this.listener;
>>>>        }
>>>> [..]
>>>> That's the simples way and should probably be sufficient. If we wanted
>>>> to get fancy, we could handle a List<PDFEventListener>.
>>>> In PDFDocumentHandler.startDocument():
>>>> this.pdfDoc.setEventListener(new PDFLibraryEventAdapter(getUserAgent().getEventBroadcaster());
>>>> So, the PDFDocument doesn't actually get an EventBroadcaster.
>>>> PDFDocument calls the PDFLibraryEventAdapter and that one in turn calls
>>>> the EventBroadcaster. Nicely decoupled.
>>>>> Thanks!
>>>>> -Mike
>>>>> On 11/05/11 19:46, Jeremias Maerki wrote:
>>>>>> Hi Michael
>>>>>> Creating a new EventBroadcaster is obviously wrong. The idea is that
>>>>>> user can get events for each FOP rendering run separately (unlike
>>>>>> logging where concurrent runs get mixed up). So you have to get hold
>>>>>> that EventBroadcaster applicable to the current rendering run. Obviously,
>>>>>> you don't have access to the FOUserAgent in the PDF library. That
>>>>>> intentional because the PDF library should remain reasonably independent
>>>>>> of as much FOP code as possible for the case that we ever factor
it out
>>>>>> into a separate component/module or move it to XML Graphics Commons.
>>>>>> My suggestion is to follow a similar path as done in
>>>>>> org.apache.fop.fonts: Create an interface for the events coming out
>>>>>> the PDF library (see FontEventListener). Let's call it PDFEventListener
>>>>>> or something like that and put it in the org.apache.fop.pdf package.
>>>>>> Then move your PDFEventProducer (corresponds to FontEventProducer)
>>>>>> org.apache.fop.render.pdf as this package makes the glue between
FOP and
>>>>>> PDF output. Then create a PDFLibraryEventAdapter (implements PDFEventListener)
>>>>>> in the org.apache.fop.render.pdf package (corresponds to
>>>>>> FontEventAdapter). The PDFLibraryEventAdapter will get the
>>>>>> EventBroadcaster from the PDFDocumentHandler which is responsible
>>>>>> instantiating the PDFDocument and PDFLibraryEventAdapter. The adapter
>>>>>> then added as listener to a List<PDFEventListener>     that
you can add to
>>>>>> PDFDocument. From PDFEncryptionJCE you should have access to the
>>>>>> PDFDocument via the getDocumentSafely() method. That nicely decouples
>>>>>> FOP's event subsystem from the PDF library.
>>>>>> HTH
>>>>>> On 11.05.2011 15:47:49 Michael Rubin wrote:
>>>>>>> ?Hello there. I have been busy implementing 128 bit PDF encryption
for FOP. I have already got it working successfully but one issue remains that I have a question
>>>>>>> In the org.apache.fop.pdf.PDFEncriptionJCE.init() method there
is one place where I want to broadcast an event message. I looked athttp://xmlgraphics.apache.org/fop/trunk/events.html
 to learn about events. However it just shows "EventBroadcaster broadcaster = [get it from
somewhere];" and doesn't show how I should be getting the broadcaster. After looking in the
code in the AFP package for existing examples I put together the following which seems to
work on testing:
>>>>>>> FopFactory fopFactory = FopFactory.newInstance();
>>>>>>> FOUserAgent agent = fopFactory.newFOUserAgent();
>>>>>>> EventBroadcaster eventBroadcaster = agent.getEventBroadcaster();
>>>>>>> PDFEventProducer eventProducer = PDFEventProducer.Provider.get(eventBroadcaster);
>>>>>>> eventProducer.warnRevision3PermissionsIgnored(this);
>>>>>>> This creates a new FopFactory, from which I create a new FOUserAgent,
from which I can get the event broadcaster to supply to my event producer. (I had to create
a PDFEventProducer which extends EventProducer. Plus PDFEventProducer.xml which contains the
message mapping.)
>>>>>>> In this case the EventBroadcaster will be created new every time
so I am not sure existing listeners will pick up. So is there a recommended way that I can
get an existing event broadcaster to use? Or is the above way the correct way to do it after
>>>>>>> Version of FOP is v1.0. Platform is Ubuntu Linux, running from
within the Eclipse IDE.
>>>>>>> Thanks!
>>>>>>> -Mike
>>>>>>> Michael Rubin
>>>>>>> Developer
>>>>>>> T: +44 20 8238 7400
>>>>>>> F: +44 20 8238 7401
>>>>>>> mrubin@Thunderhead.com
>>>>>>> The contents of this e-mail are intended for the named addressee
only. It contains information that may be confidential. Unless you are the named addressee
or an authorized designee, you may not copy or use it, or disclose it to anyone else. If you
received it in error please notify us
>>>>>>> immediately and then destroy it.
>>>>>> Jeremias Maerki
>>>> Jeremias Maerki
>> Jeremias Maerki

View raw message