Page 1 of 1

Oxygen Author Component performance

Posted: Thu Dec 18, 2014 1:28 pm
by alexandr.golovach
Hi, Oxygen guys!
As you may know, we are using Oxygen web Component in our Ditaworks Cloud application as a main topic editor.
In our oxygen customization we overrided standart Oxygen's api classes - StylesFilter and AuthorReferenceResolver.
I see some problems with Oxygen performance when opened document contains some conrefs and images.
I have some questions about Oxygen Author Component performance with our extensions.

1. About StylesFilter. We used our StylesFilter implementation - DITAStylesFilter. I noticed that DITAStylesFilter is called very often even in normal content scrolls. In this case, the filter called all the AuthorNode of the AuthorDocument.
Who controls the behavior of the DITAStylesFilter?
Can we manage call DITAStylesFilter?
Сan we only use the cache inside the DITAStylesFilter to solve this problem?

2. About AuthorReferenceResolver.We used our AuthorReferenceResolver implementation - DITAReferenceResolver. Consider a simple example - I inserted 5 conref elements in opened topic - DITAReferenceResolver works great. Then I turn on the Text page in editor and add some changes in content, which aren't linked with inserted conrefs element. After that I turn on the Author page - DITAReferenceResolver is called all the AuthorNode of the AuthorDocument. But if I don't added some changes in content in Text mode, DITAReferenceResolver isn't called when I turn on Author page again.
Who controls the behavior of the DITAReferenceResolver?
Can we manage call DITAReferenceResolver?
Сan we only use the cache inside the DITAReferenceResolver to solve this problem?

when I saw the source your Oxygen Author SDK samples in Maven repository, I opened your DITAConRefResolver class. This class contains field

Code: Select all

private Object grammarCache = null;

which used in resolveReference() method.

Code: Select all

 XMLReaderWithGrammar readerWithCache = authorAccess.getXMLUtilAccess().newNonValidatingXMLReader(grammarCache);
XMLReader xmlReader = readerWithCache.getXmlReader();
grammarCache = readerWithCache.getGrammarCache();
How to use this grammarCache object?

Regards,
Alex

Re: Oxygen Author Component performance

Posted: Thu Dec 18, 2014 4:11 pm
by Radu
Hi Alexandr,

Please see some answers below:
1. About StylesFilter. We used our StylesFilter implementation - DITAStylesFilter. I noticed that DITAStylesFilter is called very often even in normal content scrolls. In this case, the filter called all the AuthorNode of the AuthorDocument.
Yes, the filter is asked for styles every time the swing canvas which renders the Author visual layout is repainted. And repaints happen a lot.
Who controls the behavior of the DITAStylesFilter?
There is no styles filter set for DITA by default. You probably created your own.
Can we manage call DITAStylesFilter?
Our code calls the styles filter extensions every time we need to find out styles for a certain node, so you cannot control how often it gets called.
Сan we only use the cache inside the DITAStylesFilter to solve this problem?
Yes, it is recommended that you use a local cache to avoid lots of computation every time the styles filter is asked to contribute extra styles.

If you would give us more details about what your styles filter does, maybe we could try to see if maybe there is an approach of doing this using CSS instead of a Java extension.
2. About AuthorReferenceResolver.We used our AuthorReferenceResolver implementation - DITAReferenceResolver. Consider a simple example - I inserted 5 conref elements in opened topic - DITAReferenceResolver works great. Then I turn on the Text page in editor and add some changes in content, which aren't linked with inserted conrefs element. After that I turn on the Author page - DITAReferenceResolver is called all the AuthorNode of the AuthorDocument. But if I don't added some changes in content in Text mode, DITAReferenceResolver isn't called when I turn on Author page again.
When you switch to the Text page and make no modification to it, then switch back, nothing happens, the Author layout is not reloaded at all.
If you switch to the Text page and make a modification (any modification, big or small in any place) then switch back to Author, the entire Author document will be reloaded from the content in the Text page, it will be as if the XML is re-opened in the Author page.
Who controls the behavior of the DITAReferenceResolver?
Can we manage call DITAReferenceResolver?
Our code calls the resolvers, you do not control how often they are called or not.
Сan we only use the cache inside the DITAReferenceResolver to solve this problem?
Sure, you could for example cache the content of the target URL as a local file in the temporary files folder. Then when the resolver is called again for that URL and you need to provide a SAXSource for it, just create an input stream over the file on the local disk and construct the org.xml.sax.InputSource giving it besides the system ID of the original remote target document, an input stream over the local disk.

The problem with caches is that they would need to be invalidated at some point if the content of the remote target changes.
when I saw the source your Oxygen Author SDK samples in Maven repository, I opened your DITAConRefResolver class. This class contains field

Code: Select all
private Object grammarCache = null;


which used in resolveReference() method.

Code: Select all
XMLReaderWithGrammar readerWithCache = authorAccess.getXMLUtilAccess().newNonValidatingXMLReader(grammarCache);
XMLReader xmlReader = readerWithCache.getXmlReader();
grammarCache = readerWithCache.getGrammarCache();


How to use this grammarCache object?
That grammar caching (which already works) should cache the DTDs associated with the parsed DITA content. For example DITA topics are very small but they refer to DTDs which usually are quite many. So when you parse a small DITA topic without grammar caching, the XML parser (Xerces in our case) will also parse about 10 DTDs in order to contribute default attribute values to the DITA content.
So that grammar caching is only for the DTDs referenced from the XML document, we keep the internal model of parsed DTDs and reuse that model for parsing XML documents without having to parse again the DTDs.

Regards,
Radu

Re: Oxygen Author Component performance

Posted: Wed Dec 24, 2014 4:01 pm
by alexandr.golovach
Hi, Oxygen guys!
I tried to use your suggestions about creating cache in our implementation classes, but my problem wasn't solved.
I have some questions about WSEditorPageChangedListener.

1. I added WSEditorPageChangedListener in our Oxygen Author Component.
Consider a simple example - I inserted 5 conref elements in opened topic - DITAReferenceResolver works great. I tried to measure operation time in editorPageChanged() method. This method works off about 100 milliseconds.
DITAReferenceResolver works off 2 second for all references if I used cache. But when I used our Applet as simple user I saw that page switching from Text to Author worked off 7 second.
Where to spend another 5 seconds?
May be I made the wrong measurement time? How should I make the right measurement?
What methods are called within AuthorComponent?
I see a big problem with Oxygen performance. How should I fix it?

2. In my first case I didn't tri to measure operation time in DITAStylesFilter - it's so diffical, DITAStylesFilter is called very often. In DITAStylesFilter I used this code for download images:

Code: Select all


    StringBuilder request = new StringBuilder();
request.append("repository_root?sourceDocPath=");
request.append(sourceDocPath);
request.append("&destDocPath=");
request.append(decodeLink(attrValue.getValue()));

String url = baseUrl + "/";

styles.setProperty(Styles.KEY_MIXED_CONTENT, new StaticContent[] { new URIContent(url, request.toString()) });
How do Oxygen StylesFilter cashe this URIContent? May be I need to use my spetific cache? May be DITAStylesFilter works off 5 seconds?

Regards,
Alex

Re: Oxygen Author Component performance

Posted: Mon Dec 29, 2014 3:07 pm
by alex_jitianu
Hi Alex,

1. The best idea would be to use a profiler tool to identify the execution hotspots, for example JProfiler. In JProfiler you can also see the time a thread spends waiting for an I/O operation (which might also be a cause for the latency). JProfiler for example can also connect to a running JVM so you could start the applet, connect the profiler to it, start the monitoring and then switch from text page to the author one.

Another possibility is to comment your extension points one by one (if possible) and see if the latency disappears.

2. Yes, the StylesFilter is called quite often. Oxygen has an internal style cache but it stores the original styles. Every time the styles are requested, the original styles are taken from the cache and passed through the StylesFilter. If you are doing extensive processing on the filter() method then it is recommended to create your own caching mechanism using an java.util.WeakHashMap<AuthorNode, Styles[]>. The key should be the author node and the value the styles for the element itself and the BEFORE/AFTER elements. Please make sure to avoid using pseudo elements as the key, like this:

Code: Select all

AuthorNode key = authorNode;
if (authorNode.getType() == AuthorNode.NODE_TYPE_PSEUDO_ELEMENT) {
key = authorNode.getParent();
}
You should also keep a reference to the original Styles in order to detect when these change (you can use equals() on Styles objects). In this situation you must drop the cache and recompute the styles.

Anyway, if you want to find out if the filter is the cause for latency you could just comment it out and see if the latency disappears or not.

As far as the images case goes, I see that you are just giving the URL to the image. Oxygen has a built-in cache for images. This cache has a limit or 30MB. Do you you have a great number of images in this document? What's the average size for an image? If you find out that the images are the cause of the lag then we can talk about possible solutions, for example a mechanism to lazy bring images to the local disk and refresh the corresponding nodes when they are available.

Best regards,
Alex

Re: Oxygen Author Component performance

Posted: Wed Dec 09, 2015 2:48 pm
by Konstantin
Hi, Oxygen guys!
After update 17.1.0.1 our custom classes which implement :
- StylesFilter
- AuthorReferenceResolver
don't work.
They are not called, and the debugger does not go into them.
Could you tell what happened in the update and how to fix it?

Also in the 17th update removed the annotation @API
As I understand now they can just delete without substitute. Is it so ?

Re: Oxygen Author Component performance

Posted: Thu Dec 10, 2015 10:22 am
by Radu
Hi Konstantin,

How exactly are you using our SDK, are you using it as a Maven project or just downloading the ZIP containing all JAR libraries and using it as such?

About the removed annotation @API, the 17.1 SDK should now contain a new JAR library called "oxygen-annotations.jar" which should be used for compilation. From your custom Java code you can also remove those annotation markers. We use those only internally when compiling the main Oxygen JAR libraries.

About the StylesFilter and the AuthorReferenceResolver not working, could you give me more details?
Have you updated all the JAR libraries to the ones which come with the 17.1 SDK or only some of them?
Are you setting those up via a custom ExtensionsBundle extension or as separate extensions in the custom framework configuration you have?

If you are using a custom ExtensionsBundle and you look in the debugger, are its API methods createAuthorStylesFilter called by Oxygen?
If you have edited the document type (framework) configuration in the Oxygen Preferences->"Document Type Associations" page and in the Extensions tab you have set your custom styles filter, could you try to make sure that the framework bundled with the component in the frameworks.zip.jar contains those changes?

Regards,
Radu

Re: Oxygen Author Component performance

Posted: Mon Dec 14, 2015 10:41 am
by Konstantin
Thanks for the help.
Helped description handlers in dita.framevork

Code: Select all

<field name = "cssStylesFilterExtension">
<String> ro.sync.ecss.extensions.api.DITAStylesFilter </ String>
</ field>
and

Code: Select all

<field name = "customReferencesResolver">
<String> ro.sync.ecss.extensions.dita.conref.DITAReferenceResolver </ String>
</ field>

Re: Oxygen Author Component performance

Posted: Mon Dec 14, 2015 2:44 pm
by Radu
Hi Konstantin,

Let's first try to look into the styles filter extension problem:

So I made some small tests on my side, created a Java class called DITAStylesFilter which extends StylesFilter.
I placed it in a package ro.sync.ecss.extensions.api because I wanted to have something similar to what you wanted.
I compiled the extension class and placed it in a separate JAR file.
I edited the custom DITA framework I had using Oxygen standalone. First I defined a custom frameworks location in the Oxygen Preferences->Document Type Association / Locations page and then in the Preferences->Document Type Association page I edited my custom framework, added in the "Classpath" tab a link to my new JAR library and in the Extensions tab I added my Styles Filter implementation.
Then I created the "frameworks.zip.jar" containing my customized framework folder and used it with the component.
It worked for me, the styles filter extension was used and its filtering method was called.

Could you check a couple of things on your side?
1) Do you have a separate JAR library which contains that ro.sync.ecss.extensions.api.DITAStylesFilter extension?
Could you look inside it to see if the extension was properly compiled and packed?
2) Did you add a reference to that JAR library in the Classpath list from the framework configuration?
3) Are you editing the ".framework" manually instead of using the Oxygen standalone installation to edit it visually? I would advice against making manual modifications because maybe you are making changes in the wrong place.

Regards,
Radu