Minor issues with Placeholder

Hello,

I’m quite new to DockingFrames and startet from the PlaceholderExample. I’m very impressed - what already works out of the box :slight_smile:
Very nice work!
I changed DockController to DockFrontend to be able to store/restore the layout.

Things work fine - at first sight.

My issues:

  • the size of the frame is not saved/restored.
  • when I hide a placeholder and close the app (storing of layout is handled at windowClosing event) and restart it again, the hidden placeholder will be restored to a big oversized part at first location - no more relation to the placeholder, it was part of.

Do I need to extend the CustomDockable to get the placeholder saved as well?
What do I need to do, to get the framesize stored as well?

br

Gero

DockFrontend makes a lot of things easier, using the Common project and CControl instead of DockFrontend/DockController makes things even more easier :wink:

  • the size of the frame is not saved/restored.

The size of the frame is outside of the scope of DockingFrames. I would make a lot of people unhappy if the framework would start to resize frames… you just have to store its size and location yourself.

  • when I hide a placeholder and close the app (storing of layout is handled at windowClosing event) and restart it again, the hidden placeholder will be restored to a big oversized part at first location - no more relation to the placeholder, it was part of.

This could happen if the Dockable has a big minimum size (see Component.getMinimumSize). I would need to see the code you are executing, it could be an issue with the configuration.

Do I need to extend the CustomDockable to get the placeholder saved as well?

You need a relation between Dockable and placeholder, how exactly you get that relation is not important. Subclassing CustomDockable is an option, but you could also fill a map with Dockable-placeholder relations.

Or use Common, where you don’t need to deal with placeholders directly (ok, you deal with „unique identifiers“ which is a bit similar, but you don’t need to store them yourself).

What do I need to do, to get the framesize stored as well?

You could for example write the framesize into the DataOutputStream or the xml file before you call „write/writeXML“ on DockFrontend. Or you write your own file with the size. The framework won’t store it for you, there is no such feature available.

The size of the frame is outside of the scope of DockingFrames.

At first thought - this is a statement, I can live with. Maybe I overread it from documentation.

At second thought - that statement is like splissing hairs.
If Dockstation is the client-Area of a frame, there’s no reason, why the frame shall be outside of the framework and I’m quite sure, noone will be unhappy,
if such a frame get’s its size restored (after all, its the size, the user has choosen).
If the stations parent is not the frame himself, the frame’s size should of cause not be touched in any case.

So I think, there’s a deterministic way to choose, when the frame should be part of the frameworks resized windows.

This could happen if the Dockable has a big minimum size (see Component.getMinimumSize). I would need to see the code you are executing, it could be an issue with the configuration.

If happens even on empty JPanels without touching the preferred size / minimum size.
… any way: if you tell me a way to transmit my code privately, I’ll do.

You could for example write the framesize into the DataOutputStream or the xml file before you call „write/writeXML“ on DockFrontend. Or you write your own file with the size. The framework won’t store it for you, there is no such feature available.

If I have to mix my savings with savings from docking frame, I won’t use readXML most probably.
Have to dig further to find out how things could be solved.

… by the way:
I forgot to mention an exception in my first post, that I get the first time, I move a dockable to different location:

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at bibliothek.util.workarounds.Java6Workaround.makeTransparent(Java6Workaround.java:72)
	at bibliothek.util.Workarounds.makeTransparent(Workarounds.java:129)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator$ImageWindow.<init>(DefaultDockRelocator.java:1150)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator.getTitleWindow(DefaultDockRelocator.java:940)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator.initiateOperation(DefaultDockRelocator.java:622)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator.dragMouseDragged(DefaultDockRelocator.java:587)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator.dragMouseDragged(DefaultDockRelocator.java:541)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator.dragMouseDragged(DefaultDockRelocator.java:520)
	at bibliothek.gui.dock.control.relocator.DefaultDockRelocator$MouseRepresentativeListener.mouseDragged(DefaultDockRelocator.java:1093)
	at java.awt.AWTEventMulticaster.mouseDragged(AWTEventMulticaster.java:303)
	at java.awt.AWTEventMulticaster.mouseDragged(AWTEventMulticaster.java:302)
	at java.awt.Component.processMouseMotionEvent(Component.java:6338)
	at javax.swing.JComponent.processMouseMotionEvent(JComponent.java:3285)
	at java.awt.Component.processEvent(Component.java:6059)
	at java.awt.Container.processEvent(Container.java:2039)
	at java.awt.Component.dispatchEventImpl(Component.java:4653)
	at java.awt.Container.dispatchEventImpl(Container.java:2097)
	at java.awt.Component.dispatchEvent(Component.java:4481)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4575)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4253)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4166)
	at java.awt.Container.dispatchEventImpl(Container.java:2083)
	at java.awt.Window.dispatchEventImpl(Window.java:2482)
	at java.awt.Component.dispatchEvent(Component.java:4481)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:648)
	at java.awt.EventQueue.access$000(EventQueue.java:84)
	at java.awt.EventQueue$1.run(EventQueue.java:607)
	at java.awt.EventQueue$1.run(EventQueue.java:605)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
	at java.awt.EventQueue$2.run(EventQueue.java:621)
	at java.awt.EventQueue$2.run(EventQueue.java:619)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:618)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: java.lang.IllegalArgumentException: The window must use a translucency-compatible graphics configuration
	at com.sun.awt.AWTUtilities.setWindowOpaque(AWTUtilities.java:378)
	... 46 more

may be you could (optionally?) silence the exceptions output.

br

Gero

Sorry for the late reply, I was not around yesterday and won’t be around today neither.

If happens even on empty JPanels without touching the preferred size / minimum size.
… any way: if you tell me a way to transmit my code privately, I’ll do.

You can send me a mail, at benjamin_sigg@gmx.ch. I’ll delete your code from my machine once the issue is solved.

[QUOTE=geronimo]At first thought - this is a statement, I can live with. Maybe I overread it from documentation.

At second thought - that statement is like splissing hairs.
If Dockstation is the client-Area of a frame, there’s no reason, why the frame shall be outside of the framework and I’m quite sure, noone will be unhappy,
if such a frame get’s its size restored (after all, its the size, the user has choosen).
If the stations parent is not the frame himself, the frame’s size should of cause not be touched in any case.

So I think, there’s a deterministic way to choose, when the frame should be part of the frameworks resized windows.[/quote]
I agree that this would be a very comfortable feature, but I don’t agree that it would be good design.

  • How do you find out whether a DockStation is the client-area? Check it the parent container is a Window? What happens if the application inserts another JPanel between window and DockStation, for example because it wants to show a JToolbar? Then the behavior changes, this would be a very unintuitive behavior.
  • What happens if you want your frame to appear at the same position all the time? For example because the frame is a sub-frame of another application? I already see the first post in this forum „Bug: frame ignores position and size when using DockingFrames“…
  • It’s also not backwards compatible, all applications are already programmed with the knowledge that DF does not tamper with the frame size. And if the feature is disabled per default, then most people won’t find it anyway.
  • Finally, any respectable application stores a number of setting, e.g. which folder was last open in the JFileChooser. Most application will need their custom settings-file anyway, so not having this feature does not generate (much) more work for developers.

If I have to mix my savings with savings from docking frame, I won’t use readXML most probably.
Have to dig further to find out how things could be solved.

You can create your own XElement-objects, and use the methods from XIO to read/write your own xml files.

… by the way:
[…]
may be you could (optionally?) silence the exceptions output.

Yeah, I think i remove the output completely. It does not tell anything useful nor anything that needs to be changed. The issue will solve itself once JRE 6 is no longer in use.

Sorry for the late reply

Never mind!

It’s sunny outside, so there’s no reason to be docked to your desktop :wink:

You can send me a mail …

Thanks a lot for that offer!

I followed your advice and changed to commons usage.
Now sizes will be saved even if the window is hidden. And restoring works as expected.
Very nice!

I agree that this would be a very comfortable feature, but I don’t agree that it would be good design.

Agree.
… but I keep thinking, that if someone puts a JPanel between DockingStation and the JFrame, the DockingStation is not at top-level.

Never mind.

As you already guessed, I have more items to save and read.
Currently I use separate files, as I use plain text for my configuration and I currently support the user to edit that file.
I’d like the idea to merge both configuration savings, but I don’t like to bother with xml, nor do I want to use binary format.

Java Preferences is a fine layer.
With Preferences, the application could serve a virtual root node and if docking frames would support Preferences, all doggy bags could be stored in the applications area :wink:

br

Gero

Well, looks like your problems are solved then?

Personally I like the Java preferences as well. I won’t adapt the framework to use them for the simple reason that it would be too much work… we are speaking of at least 20 classes that store things. And all of them have to be maintained if new features are added. But I guess one could write a converter to store the xml structure in the preferences.

Well, looks like your problems are solved then?

Yep - thanks a lot.

I won’t adapt the framework to use them for the simple reason that it would be too much work… we are speaking of at least 20 classes that store things.

Hm, do you mind to send me a list of that classes? (email is enabled in my profile)

I have a bigger app, that uses preferences for lot of different storage issues and I don’t have any problems with change-support or extra work for preferences.
I believe, that a converter for xml to preferences is the most expensive solution - and after all - I don’t like that design!

In my app I use some kind of pluggable writers, so the same entity can be saved as xml, preferences, database entry or plain text without any change to the entity itself.
I’d like to look at the referred classes. May be I can post you an idea or even a patch.

… anyway - I think, the cleanest way to store versatile things without having you to care for any format used, is to rename

CControl.getResources().writeFile(File f)

to

CControl.getResource().write(ObjectWriter ow)
  • so the application designer can choose the format and location to store things to.
    That ObjectWriter needs just one method:
write(String key, Object value)

That way, you could provide a Writer for the format of your choice and any user could implement a different Writer, if he likes a different format.

best regards

Gero

Careful, wall of text ahead…


History and the effect on your suggestion
Unfortunately you are right, using an interface like you described would be a better way to handle things than they are handled right now. The way persistent storage works now is because of the history of the framework: in the first iteration only the byte-format existed. Back then just forwarding a ByteStream was good enough.
Then xml was added. At first it was more a gimmick, it was actually a tool to more easily test and debug the storage mechanism. So I added only a very few methods and xml was in the system.
Only 1-2 years later the complexity of the storage mechanism exploded. By adding placeholders, the perspective API and more complex recovery tools to handle incomplete/broken layouts, the amount of code involved in storage easily quadruplet.
But the basic design, of using byte streams and xml directly already was set. And because all of this happened in very small steps, I always backed away from changing the entire system.

Now the framework is stuck with it, there is no way to change it without seriously breaking backwards compatibility. Because clients need to implement interfaces like “DockFactory” using a new system would affect almost all clients, and that’s something I simply cannot do.

So you see: I agree with you, I even like your solution, but non-technical reasons do not allow me to implement it.


A word to xml vs. preferences
You said you do not want to convert xml to preferences. I just want to add that the output of your solution would be very similar to a conversion. Because you certainly do not want a complex ObjectWriter you will usually use it to store things like a “String” or a “double”. The hard work - finding out which data is important and must be stored - is not done by the ObjectWriter, but by its callers. Well, that is what the xml file does as well…


The objects creating the layout
You need to know, that layout information appears in different formats. There is xml and binary of course, there are the actual Components you see on the screen, and there is the perspective API which offers an interface similar to the real components. All of these formats are converted into each other going through an “intermediate format”, and if you really want to implement a new format you are going to work with this intermediate format.

The intermediate format consists of:
[ul]
[li]DockLayoutComposition - building a tree, each DockLayoutComponent represents one DockElement
[/li][li]DockLayoutInfo - wrapper around a DockLayout
[/li][li]DockLayout - denotes the name of a factory and the data that can be read by said factory
[/li][li]The “L” generic of DockFactory - the data actually describing the content of one DockElement. There are about 15 different DockFactories around, each using another type of data. Most of these layout-objects are quite simple.
[/li][li]MultipleCDockableLayout - a little bit like the “L”, classes implementing this interface are defined by the client.
[/li][li]PlaceholderMap - a generic map, mostly stores Strings, ints, and things like that. No complex objects.
[/li][/ul]

Further more these classes are showing up:
[ul]
[li]DockSituation - this class is responsible from converting data from one format into the other format.
[/li][li]DockableProperty - around 7 subclasses, they are nested. Describe the local location of a Dockable, need to be stored as well.
[/li][li]CSetting/Setting - represents one layout (multiple stations)
[/li][li]ModeSettings - information about modes like “minimized”.
[/li][li]ModeSetting - information about a single mode, there is actually only one implementation of this interface, but it needs to be stored.
[/li][li]SettingsBlop? - This class is new (I wrote it last weekend) and represents the settings of the entire framework. I have not yet published this class, but I think it would be your entry point for reading/writing the settings. I do not yet know how it will be accessed.
[/li][/ul]

Hi Beni,

thanks a lot for taking the time for such an detailled response!
I’m sorry, I was not so detailled in my sugestion, so there are some misunderstandings …

You said you do not want to convert xml to preferences. I just want to add that the output of your solution would be very similar to a conversion.

Well, the difference is very small and in fact, I only mind the conversion, not the support of xml format.

I wrote a persistence layer, that supports xml, databases and preferences for the same pojo objects. It’s not a trivial task and I also know the hysteric reasons, why things are tied to the current state.
I don’t believe, that making things right means compatibility must be broken. But ok - I don’t know enuf to know it right.

Because you certainly do not want a complex ObjectWriter you will usually use it to store things like a „String“ or a „double“. The hard work - finding out which data is important and must be stored - is not done by the ObjectWriter, but by its callers.

No!

Here you definitely took me wrong. I did not talk about ObjectOutputStream or DataOutputStream - I really want to handle the Complexity in the ObjectWriter. So you use i.e. ObjectWriter.write(„path of property“, DockableProperty) or the like. If it is not appropriate for your code, you might consider split your classes into compound classes, where one class is the saveable and the surrounding class is the functionality. That way you simply put the saveable in the write-call.

With preferences you have a duality of user-preferences and system-preferences - so in my layer I support the saveables have a list, that contains the user-properties. My reader than first reads all properties from system-preferences (if exists). Then it reads the „user-properties“ from user-preferences and overwrites the properties.
On saving such instances the writer checks the write-permission to system-preferences (which usually will fail). If system-write-permission exists, a system preference will be written, otherwise the user-properties will be stored in user space.
In my persistence-layer I did the grunt work once, which means, I heavily used introspection, reflection and other expensive stuff. But at benchmarking my layer it was not as bad as expected :wink:
The good point is, the application (and their developers of cause) benefit from the ease of usage.

You need to know, that layout information appears in different formats.

I very hope, the different formats will only be on disk and not in your framework code.
My current app using docking frames is very small - only 4 dockables in one frame.
I’m very astonished, that the stored layout uses 4k diskspace in binary format. Looks quite a lot to me.

if you really want to implement a new format you are going to work with this intermediate format.

OK. I’ll have a look at it.
But that does not have a big priority yet, as I’m stil focused on implementing functionality.
and as a wise man said: first make it work …

BR

Gero

If and when you want to write a new persistence layer of the framework is of course up to you. If you want to seriously work on this let me know, I’m certain your are going to miss some methods you need to access the layout data… :smiley: We may even talk about you having write access to the repository.

I don’t believe, that making things right means compatibility must be broken. But ok - I don’t know enuf to know it right.

Well, maybe it could be solved by duplicating some interfaces (don’t like that idea)… but it would be a long term project, slowly migrating from one system to the other giving everyone enough time to react and rewrite their parts.

I very hope, the different formats will only be on disk and not in your framework code.

Let me answer this with an image:

All of the formats have different roles, in which they are especially efficient:
[ul]
[li] Actual layout: well, there is no way around that one :wink:
[/li][li] Perspective: a very simplified version of the actual layout, without the gigantic overhead of Components, code that paints stuff, etc… a client can create a few million perspective elements, you better don’t try that with the actual layout.
[/li][li] Intermediate: If some property is in the intermediate format, then it is important. Anything not in the intermediate format is not important. It is designed to be easily written into a file, but modifying the layout when it is in this format is really hard.
[/li][li]Xml / bytes: self explanatory I hope
[/li][/ul]

Here you definitely took me wrong. I did not talk about ObjectOutputStream or DataOutputStream - I really want to handle the Complexity in the ObjectWriter. So you use i.e. ObjectWriter.write(„path of property“, DockableProperty) or the like. If it is not appropriate for your code, you might consider split your classes into compound classes, where one class is the saveable and the surrounding class is the functionality. That way you simply put the saveable in the write-call.

Yes, I misunderstood you.

It seems you put a lot of work in your persistence layer :wink: What I call the „intermediate format“, is close to your ObjectWriter. The intermediate format is „the saveable part“ and nothing else. In order to get from actual layout to a file on the disk, I need 2 steps. The ObjectWriter would need only 1 step.

But because the framework needs to perform some operations on stored layouts (guessing the type and location of Dockables whose factory is added after the layout was loaded; removing obsolete placeholders), I need to store and access the layout in memory anyways. Looking at the image of formats, using your ObjectWriter would result in different arrows, but the same amount of boxes at the same places.

My current app using docking frames is very small - only 4 dockables in one frame.
I’m very astonished, that the stored layout uses 4k diskspace in binary format. Looks quite a lot to me.

Nice app. Und wie ich sehe, hätten wir uns auch auf Deutsch unterhalten können. I can easily explain how 4k data is gathered: Let’s assume the usual identifier for a factory, a CStation or a CDockable consists of about 20 characters. So each stored identifier is going to need about 40 bytes.
→ 4 Dockables, 6 Stations: 400 bytes alone to assign factories to these elements.
→ Another 10*40=400 bytes alone to store the identifiers of these elements.

Each station has a layout, and the layout contains „placeholders“ - identifiers to elements that were moved around.
→ Assuming you clicked around a bit: 3 placeholders per dockable, another 12*40=480 bytes.
→ The layouts themselves usually are serialized maps, maybe another 200 bytes / station: 1200 bytes (that was guessed)

Each Dockable stores one location per extended-mode („minimized“, etc). Each location contains a placeholder.
→ 4 * 4 * 40 = 640 bytes

By now we are at 3120 bytes, and I did not even start of speaking about delegate factories, automatically created nested DockStations, PlaceholderMaps for removed nested DockStations…

I suggest you store the layout as xml file and have a look at it, I always think it gives a good impression on what is going on inside the framework.

[quote]I don’t believe, that making things right means compatibility must be broken. But ok - I don’t know enuf to know it right.
Well, maybe it could be solved by duplicating some interfaces (don’t like that idea)… but it would be a long term project, slowly migrating from one system to the other giving everyone enough time to react and rewrite their parts.[/quote] Hm, I think, the best way to start is start thinking different.

All of the formats have different roles, in which they are especially efficient

Not sure, but I got the impression, you made your life a bit too complicated.

But because the framework needs to perform some operations on stored layouts …

No sir - I believe, that’s definitely wrong overkill.

If you split the functionality in responsability layers and then look, when certain action happens …
… well, from the applications I know, there’s one time, where configuration data gets read (the applications startup) and one time, when configuration data gets written (the applications shutdown). This is even true for application that uses dynamically loaded application modules, that may bring up their own toplevel window …
All changes, that happen in the lifetime between these two points should never think or even care about persistence. Just change properties of beans.

Most users already know, that startup and shutdown of applications takes some time.
As an application designer I’ll like to read independant configurations in multiple concurrent threads to speed up application start, but that’s definitely beyond the scope of frameworks like docking frames. But to enable such design decisions its evident, that the framework is not tied to persistence, but uses independant „Transformers“, that could work in parallel …

Intermediate: If some property is in the intermediate format, then it is important. Anything not in the intermediate format is not important. It is designed to be easily written into a file, but modifying the layout when it is in this format is really hard.

Reading this, I’m convinced, that your Intermediate is designed suboptimal. It should be designed to perform well during lifetime of application and for so scale well.
Optimization for persistence should not happen here.

It seems you put a lot of work in your persistence layer

If you like to take a look[ul]
[li] framework
[/li][li] app
[/li][/ul]
When I started with both, I wanted to think different and not care about mainstream. Result is not bad, but when I started my youngest app (the one that uses docking frames), I realized, that my framework is tied to persistence and persistence decisions the much. So I have to start a rewrite to gain freedom.
The app is going to be rewritten to use docking frames too.
So my current app is some kind of prototype doing so :wink:

kind regards

Gero

I had the entire day to think about your answer… well, actually I had to work writing migration scripts for a database :wink:

Reading this, I’m convinced, that your Intermediate is designed suboptimal.

Don’t worry, I think the same thing. Actually there are a lot of modules in the framework that are suboptimal, the intermediate format is not the worst offender by far. If someone would pay me a million euros I would rewrite the framework from scratch, eliminating all these issues. Unfortunately that has not yet happened. :o)

Not sure, but I got the impression, you made your life a bit too complicated.
[…]
No sir - I believe, that’s definitely wrong overkill.
[…]
If you split the functionality in responsability layers and then look, when certain action happens …
[…]
All changes, that happen in the lifetime between these two points should never think or even care about persistence. Just change properties of beans.
[…]
designed to perform well during lifetime of application
[…]
Optimization for persistence should not happen here.

I think these are the parts I’d like to comment in one answer. I’ll file „read configurations concurrently“ under „premature optimization“… :wink: Some of your comments are caused either by my bad explanations, or by not fully understanding the inner workings of the framework. Especially the comment about the responsibility layers is just wrong, it is very clear which layer (or in this case „format“) has which job, and why it does have this job.

I also want my code that is writing/reading files to be easy, especially because I need to write new code for each file-format. That’s why I think the intermediate format should be optimized for persistence. At some point the conversion between Java-Object and „data“ must happen, I preferre it to happen one time only and not for each file-format (if you worry about the two arrows going to perspective api and actual layout: these two formats are so close, that they share a lot of code).

You speak about overkill, probably thinking that all this complexity - removing obsolete data on first sight, recovering data when a factory is missing, having perspectives and an intermediate format which seems to be the same thing - is not necessary. The earlier versions of the framework did not have these things, so there must be a reason why they exist now. They were added because the framework lives in a hostile environment. Since you have your own framework written, you certainly made the same experience than I did: there is always some new developer, not yet able to read a StackTrace, using your framework. I can imagine 100 different ways to subclass „de.schwarzrot.data.Entity“ and implement the methods the wrong way. Your new developer will hit one of these wrong ways. He will run to you, beg for your help… it gets annoying if the same issues show up all the time.

Many of my design decisions have the goal of eliminating the potential for misuse. And I guess in this respect the 5 formats performed well enough, because you are the first developer speaking about it in a long time. About the potential for misuse: because of the intermediate format, everything is forced through the same channels. These channels…
[ul]
[li]… enforce typesafety, if it compiles you probably did not do anything wrong.
[/li][li]… can validate and repaire data, allows to catch issues early before they get really hard to find and fix.
[/li][li]… handle changed configurations, e.g. missing factories are no issues. If necessary a converter to rename identifiers would be easy to implement.
[/li][/ul]

If you like to take a look[ul]
[li] framework
[/li]> [li] app
[/li]> [/ul]
When I started with both, I wanted to think different and not care about mainstream. Result is not bad, but when I started my youngest app (the one that uses docking frames), I realized, that my framework is tied to persistence and persistence decisions the much. So I have to start a rewrite to gain freedom.
The app is going to be rewritten to use docking frames too.
So my current app is some kind of prototype doing so :wink:

I did have a small look at them, and I will have a longer look another day. The first impression is good, but I was missing some kind of help to find out what features are offered.

Especially the comment about the responsibility layers is just wrong, it is very clear which layer (or in this case „format“) has which job, and why it does have this job.

Misunderstanding is an option - always.

I also want my code that is writing/reading files to be easy, especially because I need to write new code for each file-format. That’s why I think the intermediate format should be optimized for persistence. At some point the conversion between Java-Object and „data“ must happen, I preferre it to happen one time only and not for each file-format (if you worry about the two arrows going to perspective api and actual layout: these two formats are so close, that they share a lot of code).

I agree completely these statements.

My objectives rised from this statement:

It is designed to be easily written into a file, but modifying the layout when it is in this format is really hard.

What I understood from this:
You did some optimizations for persistence with the drawback of changing it during runtime.
For me, changing the layout during runtime is the task with the biggest priority - everything else has to subordinate.
I think, I should focus the „when“ from your statement.
Or let me ask this way: what is the lifetime of the intermediate format respect to application lifetime?
Does your runtime layout depend on the intermediate format, or can it live without it?

I did have a small look at them, and I will have a longer look another day. The first impression is good, but I was missing some kind of help to find out what features are offered.

Talking about my framework will be quite off topic here, so your welcome to write directly to me. Either per personal email or by joining one of my projects ML :slight_smile:

BR

Gero

Ok, this really seems to need some more explanation. Have a look at the image below, each arrow represents an interaction between different layers of the application, the vertical bars tell how long some layers exist (in the form of objects).

As you see, both the actual layout and the intermediate format exist during the entire lifetime of the application. However, the intermediate format is only used for storing those layouts, that are currently not in use. There is no interaction between actual and intermediate layout. The only things that can happen are:
[ul]
[li] Read access to the intermediate format to fill in missing data in the actual layout (not in the picture)
[/li][li] Read access to the intermediate format to load a new actual layout („load“)
[/li][li] Replacement of an intermediate layout to store a snapshot of the actual layout („save“)
[/li][li] One very short living intermediate layout is used to load/store the actual layout at launch and shutdown.
[/li][li] Very small modifications on intermediate layouts to keep them valid (happens when they are loaded from their file)
[/li][/ul]
Changes in the layout are performed in the actual layout only, users only interact with the green bar.

Hi,

the picture shows exactly, what I was afraid of.

… but there’s stil the possibility of misunderstanding.

What I understood from you first statement:
The optimization of the intermediate layout is to speed up the arrows from Filesystem to Intermediate layout and back.
When I just count the arrows between intermediate layout and filesystem and count the arrows between intermediate layout and actual layout - I think, if the operation between intermediate layout and actual layout has become expensive, than optimization of intermediate layout might be wrong.

… but I’m quite sure, that you measured your work, so there must have been a reason for you, to spent your time in intermediate format.

BR

Gero

I think there is bit of talking of different things :wink: You are arguing on a technical level, and most of the things you say I agree with. But for me it looks like you are ignoring one important non-technical factor: human resources.

The need to optimize for speed and memory died a few years ago when computers became really fast *. The operation behind each of the arrows takes a few milliseconds, why should I care whether it is 10 or 200 milliseconds? The user won’t notice the difference anyway. The limiting factor in todays software are the capabilities of the developer(s), how much time he/she/they need to write new features and to maintain old code.

*(Of course I will not deliberately choose the slowest algorithm if I don’t have to. I don’t care about memory though. I do care about memory-leaks :wink: )

I try to optimize what I’m capable of doing in a given amount of time. This time includes everything related to the framework: support in this forum (there are a few questions…), implementing new features, fixing bugs, writing tutorials, writing documentation, communicate with contributors. Always in respect of a codebase that has grown over many years, and incorporates requirements that were not included in the original design.

Looking at the code: Because of the intermediate format I have 2 very cheap conversions to xml and bytestream, and 1 expensive piece of code, the conversion to the actual layout. Since the perspective API and the actual layout share a lot of code, I do count conversion to perspective as good as free. Using a more complex intermediate format would give me 2 expensive conversions to xml and bytestream, and 1 cheap conversion to the actual layout. This is not desirable.

Changing the entire mechanism now would result in rewriting features that already work, thus generating work of questionable usefulness (in some companies you would be fired for just proposing such an idea). One could argue the design was wrong in the first place. That is maybe true (technical reason), on the other hand this solution was implemented fast and is easy to understand, thus less support required in the forum (non-technical reason).

But for me it looks like you are ignoring one important non-technical factor: human resources.

Here you got me wrong.

For me the cheapest and most natural way of coding would be, use just a bean as intermediate format. Access and change support can be considered cheap and fast and bringing a bean to persistence is nothing new.

So when you say, that your intermediate format is optimized for persistence, it means to me, that you spent a lot of time thinking about it and spent a lot of time for coding too.
I cannot see any benefit of such an optimization.
Following the provided sequence diagram conversion between intermediate and live layout happens quite often during lifetime of application, whereas conversion between intermediate and persistence happens exactly once for each direction. So whatever time it needs, I don’t see the necessity of optimization.

You say changing the cost of conversion towards conversion from intermediate to life-layout becoming cheap is not desirable …

Sorry, I can’t follow this.

… anyway - we talked about it, you thought about it - you don’t need to give my words any importance.
It’s your framework and it works very well - so its up to you, whether you accept a foreign trigger.

But please take for granted, that I believe, that human resource is the most valuable resource - so I think twice before spending my time on unknown/unwanted issues.
My time is my most valuable belongings and I think, you would think the same about your time.

For example, when I started with my app, I used a ready to use persistence layer, that was widely used. It was easy to start with, but at first mass operations I had to realize very bad application performance. After doing some profiling I made up my mind to write my own persistence layer. Lot of people laughed about me, but at the first competive benchmarks, my layer was about >20 times faster. I used the same technique for persistence (jdbc) so the technique could not be the difference. But I spent a little time thinking about the cost of operations and optimized those parts, that had a big impact on runtime. Additionally my time-savings where another big motivation, doing things the way I did.
There’s stil a lot of optimizations, that could be done, but the requirements to human resources does not fit the potential runtime benefit. So I did not spent any time thinking about those optimizations.

BR

Gero