Class ALcyWorkspaceCodec
- All Implemented Interfaces:
ILcdPropertyChangeSource
- Direct Known Subclasses:
TLcyBlobWorkspaceCodec
ALcyWorkspaceCodec
is responsible for encoding/decoding a workspace. Encoding a
workspace can be done using TLcyWorkspaceManager.encodeWorkspace(String)
and
TLcyWorkspaceManager.decodeWorkspace(String)
which will delegate to the methods
encodeWorkspace(String)
and decodeWorkspace(String)
of this
ALcyWorkspaceCodec
.
This class is responsible to lead the encoding/decoding process and to delegate to the registered
ALcyWorkspaceCodecDelegate
s and ALcyWorkspaceObjectCodec
s. It also deals with
(circular) references and avoids that objects are encoded twice.
A workspace is basically encoded by asking all registered ALcyWorkspaceCodecDelegate
s to
encode themselves. Whenever one of these needs to encode an object reference (e.g. a reference
to an ILcdGXYLayer
), they will use encodeReference(Object)
to do so. This
will in turn trigger this ALcyWorkspaceCodec
to find a registered ALcyWorkspaceObjectCodec
that can encode the object. Encoding such an object might trigger the
encoding of other objects, e.g. encoding an ILcdGXYLayer
l will probably trigger the
encoding of a reference to l.getModel()
.
A workspace is decoded by decoding all encoded parts by the correct ALcyWorkspaceCodecDelegate
. For every part, the ALcyWorkspaceCodecDelegate.getUID()
is used to find the correct ALcyWorkspaceCodecDelegate
, the one that encoded that part.
Decoding such a part might involve the need to restore an object reference (e.g. a reference to
an ILcdGXYLayer
). The ALcyWorkspaceCodecDelegate
will use
decodeReference(String)
to do so. This will in turn trigger this
ALcyWorkspaceCodec
to find the correct ALcyWorkspaceObjectCodec
to decode
the object. The ALcyWorkspaceObjectCodec.getUID()
is used for this purpose.
Whenever file/directory names need to be encoded/decoded by any
ALcyWorkspaceCodecDelegate
or ALcyWorkspaceObjectCodec
, it is advised
to use encodePath(String)
and decodePath(String)
. This allows subclasses for
example to store paths relative to the location of the workspace file.
Each ALcyWorkspaceCodec
also has an associated ILcdLogListener
. This
log listener can be used by all ALcyWorkspaceObjectCodec
s and
ALcyWorkspaceCodecDelegate
s to report non-fatal error/warning messages.
Furthermore, an associated ILcdStatusListener
is available to the
ALcyWorkspaceObjectCodec
s and ALcyWorkspaceCodecDelegate
s to report
about decoding status. They should report the status of the part they are currently
decoding/encoding. This allows the framework to provide a global progress monitor and a
progress monitor per task. Note however that a ALcyWorkspaceCodec
does not
report any progress of the overall decoding/encoding process, this is left to subclasses of
ALcyWorkspaceCodec
.
Subclasses must implement retrieveInputStream(String)
and retrieveOutputStream(String)
. These methods are responsible for providing access to the actual
data storage.
If needed subclasses can store an application specific header, see
createApplicationHeader()
and checkApplicationHeader(String)
for details.-
Constructor Summary
ModifierConstructorDescriptionprotected
ALcyWorkspaceCodec
(ILcyLucyEnv aLucyEnv, TLcyWorkspaceManager aWorkspaceManager) -
Method Summary
Modifier and TypeMethodDescriptionvoid
addPropertyChangeListener
(PropertyChangeListener aListener) Registers the givenPropertyChangeListener
to be notified when this object's properties change.void
addPropertyChangeListener
(String aProperty, PropertyChangeListener aListener) Adds the given listener to the list of listeners, so that it will receive notifications about changes inaProperty
.abstract boolean
canDecodeWorkspace
(String aSourceName) Returns true if the given aSourceName can be decoded.boolean
canDecodeWorkspace
(String aSourceName, List<String> aReasonsSFCT) Returns true if the given source name can be decoded, false otherwise.boolean
canEncodeReference
(Object aObject) Functionally equivalent tocanEncodeReference(aObject, null)
.boolean
canEncodeReference
(Object aObject, Object aParent) Returns true if the given aObject can be encoded.abstract boolean
canEncodeWorkspace
(String aDestinationName) Returns true if the workspace can be encoded to the givenaDestinationName
protected void
checkApplicationHeader
(String aHeader) Checks if the given header matches the expected header.protected String
Creates the application specific header.protected void
decodeFromInputStream
(String aStreamUID, InputStream aInputStream) Subclasses can use this method to tell thisALcyWorkspaceCodec
that the given stream must be decoded immediately.decodePath
(String aPath) Decodes aString
returned byencodePath(String)
into the original path name.decodeReference
(String aObjectReferenceUID) Decodes the given object reference (aObjectReferenceUID) into an actualObject
.void
decodeWorkspace
(String aSourceName) Decodes the workspace.String[]
decodeWorkspaceDelegateCodecIDs
(String aSourceName) Decodes the workspace codec delegate UID's used by the given workspace.protected void
encodeObject
(Object aObject, Object aParent, ALcyWorkspaceObjectCodec aCodec, OutputStream aOut) Called when an object needs to be encoded in the current workspace.encodePath
(String aPath) Encodes an (absolute) path (e.g. a directory or a filename) into a String.encodeReference
(Object aObject) Functionally equivalent toencodeReference(aObject, null)
.encodeReference
(Object aObject, Object aParent) Encodes the given object.void
encodeWorkspace
(String aDestinationName) Encodes the workspace.protected void
firePropertyChange
(String aProperty, Object aOldValue, Object aNewValue) Fires the given event to the associated listeners.void
Forgets the workspace storage name (e.g. the file name).Returns theILcdLogListener
to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s can report non-fatal error/warning messages that need to be reported to the end user.Returns the parent component.Returns theILcdStatusListener
to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s can report their status.Returns theTLcyWorkspaceManager
.Returns the current storage name of the workspace, this is the last aSourceName or aDestinationName passed todecodeWorkspace(String)
orencodeWorkspace(String)
.void
De-registers the givenPropertyChangeListener
from receiving property change events for this object.void
removePropertyChangeListener
(String aProperty, PropertyChangeListener aListener) Removes the given listener for the given property, so that it no longer receives those change events.protected abstract InputStream
retrieveInputStream
(String aUID) Returns anInputStream
for the given aUID.protected abstract OutputStream
retrieveOutputStream
(String aUID) Returns anOutputStream
for the given aUID.void
setLogListener
(ILcdLogListener aLogListener) Sets the log listener to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s can report non-fatal error/warning messages that need to be reported to the end user.void
setParentComponent
(Component aParentComponent) Sets the parent component.void
setStatusListener
(ILcdStatusListener aStatusListener) Sets theILcdStatusListener
to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s should report the status of the part they are currently decoding/encoding.
-
Constructor Details
-
ALcyWorkspaceCodec
-
-
Method Details
-
addPropertyChangeListener
Description copied from interface:ILcdPropertyChangeSource
Registers the given
PropertyChangeListener
to be notified when this object's properties change.In case you need to register a listener which keeps a reference to an object with a shorter life-time than this change source, you can use a
ALcdWeakPropertyChangeListener
instance as property change listener.- Specified by:
addPropertyChangeListener
in interfaceILcdPropertyChangeSource
- Parameters:
aListener
- The listener to be notified- See Also:
-
addPropertyChangeListener
Adds the given listener to the list of listeners, so that it will receive notifications about changes inaProperty
.- Parameters:
aProperty
- The property to watch for changes.aListener
- The listener to add.
-
removePropertyChangeListener
Description copied from interface:ILcdPropertyChangeSource
De-registers the given
PropertyChangeListener
from receiving property change events for this object.If the listener was added more than once, it will be notified one less time after being removed. If the listener is
null
, or was never added, no exception is thrown and no action is taken.- Specified by:
removePropertyChangeListener
in interfaceILcdPropertyChangeSource
- Parameters:
aListener
- the listener that should no longer be notified of changes of this object's properties- See Also:
-
removePropertyChangeListener
Removes the given listener for the given property, so that it no longer receives those change events.- Parameters:
aProperty
- The property to stop listening to.aListener
- The listener to remove.
-
firePropertyChange
Fires the given event to the associated listeners.- Parameters:
aProperty
- The property that was changed.aOldValue
- The old value.aNewValue
- The new value.
-
getWorkspaceManager
Returns theTLcyWorkspaceManager
.- Returns:
- the
TLcyWorkspaceManager
.
-
getLogListener
Returns theILcdLogListener
to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s can report non-fatal error/warning messages that need to be reported to the end user.- Returns:
- The log listener.
-
setLogListener
Sets the log listener to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s can report non-fatal error/warning messages that need to be reported to the end user. This listener is also responsible to inform the user of these messages. It can for example do so by writing them to the console, or by displaying them in a dialog after workspace de/encoding has finished.TLcyWorkspaceManager.addWorkspaceManagerListener(ILcyWorkspaceManagerListener)
can be used to detect when workspace de/encoding ends.- Parameters:
aLogListener
- The log listener.
-
getStatusListener
Returns theILcdStatusListener
to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s can report their status. This allows the framework to provide a global progress monitor and a progress monitor per task.- Returns:
- The
ILcdStatusListener
.
-
setStatusListener
Sets theILcdStatusListener
to which allALcyWorkspaceObjectCodec
s andALcyWorkspaceCodecDelegate
s should report the status of the part they are currently decoding/encoding. It is up to the frontend of workspace management (TLcyWorkspaceAddon
is the default frontend) to provide aILcdStatusListener
that handles the status events of the parts that are decoded. The defaultILcdStatusListener
just sends these events toILcyLucyEnv
.- Parameters:
aStatusListener
- TheILcdStatusListener
.
-
encodeWorkspace
public void encodeWorkspace(String aDestinationName) throws IOException, TLcyWorkspaceAbortedException Encodes the workspace. This method must never be invoked by user code, insteadTLcyWorkspaceManager.encodeWorkspace(String)
must be used. Encoding the workspace means all registeredALcyWorkspaceCodecDelegate
s will be asked to encode their part. When aALcyWorkspaceCodecDelegate
is encoding its part, it might need to store an object reference (e.g. a reference to an ILcdGXYLayer). It can do so usingencodeReference(Object)
. This method must only be used ifcanEncodeWorkspace(String)
for the same aDestinationName returns true.- Parameters:
aDestinationName
- The destination name of the workspace. It is up to subclasses to interpret this string, e.g. as a file name.- Throws:
IOException
- In case of fatal IO failure.TLcyWorkspaceAbortedException
- In case the operation is aborted, e.g. because the user canceled it.
-
decodeWorkspaceDelegateCodecIDs
Decodes the workspace codec delegate UID's used by the given workspace.- Parameters:
aSourceName
- The source name of the workspace. It is up to subclasses of this class to interpret this string, e.g. as a file name.- Returns:
- an array containing the UID's of the workspace codec delegates used in the given workspace
- Throws:
IOException
- if the workspace file is not compatible with this application, or if a fatal I/O exception occurs- Since:
- 2022.1
- See Also:
-
decodeWorkspace
Decodes the workspace. This method must never be invoked by user code, insteadTLcyWorkspaceManager.decodeWorkspace(String)
must be used. Decoding the workspace means all encoded parts will be decoded by the correctALcyWorkspaceCodecDelegate
. The UID is used to find the correctALcyWorkspaceCodecDelegate
. When such anALcyWorkspaceCodecDelegate
is decoding its part, it might need to restore an object reference (e.g. to an ILcdGXYLayer). It can do so usingdecodeReference(String)
.- Parameters:
aSourceName
- The source name of the workspace. It is up to subclasses of this class to interpret this string, e.g. as a file name.- Throws:
IOException
- In case of fatal IO failure.TLcyWorkspaceAbortedException
- In case the operation is aborted, e.g. because the user canceled it.
-
checkApplicationHeader
Checks if the given header matches the expected header. This method is invoked during workspace decoding. It allows applications that are built on top of Lucy to avoid reading workspaces that were written by Lucy-as-is. If the given header does not match the expected header, this method can either:- Log a warning. E.g.
getLogListener().warn( this, "Problem with header" )
- Throw an IOException to indicate that the workspace cannot be read because the header does not match.
null
, and throws an IOException if it isn't. Note that if this method is overridden,createApplicationHeader()
must be overridden as well.- Parameters:
aHeader
- The header to verify. It was read from the workspace file.- Throws:
IOException
- In case the header does not match and the workspace can therefore not be read.
- Log a warning. E.g.
-
createApplicationHeader
Creates the application specific header. This method is invoked during workspace encoding and the returned value is stored in all workspaces that are written. It allows applications that are build on top of Lucy to avoid reading workspaces that were written by Lucy-as-is. Note that applications build on top of Lucy can also use this header to store some custom version number. The default implementation returnsnull
. Note that if this method is overridden,checkApplicationHeader(String)
must be overridden as well.- Returns:
- The application specific header.
-
decodeFromInputStream
protected void decodeFromInputStream(String aStreamUID, InputStream aInputStream) throws IOException Subclasses can use this method to tell thisALcyWorkspaceCodec
that the given stream must be decoded immediately. If this method is invoked by a subclass,retrieveInputStream(String)
with aStreamUID as the argument will not be invoked anymore.- Parameters:
aStreamUID
- The UID of the stream.aInputStream
- The stream to decode now.- Throws:
IOException
- In case of read problems.
-
getWorkspaceStorageName
Returns the current storage name of the workspace, this is the last aSourceName or aDestinationName passed todecodeWorkspace(String)
orencodeWorkspace(String)
.- Returns:
- the current storage name of the workspace.
- See Also:
-
flushWorkspaceStorageName
public void flushWorkspaceStorageName()Forgets the workspace storage name (e.g. the file name). Typically the workspace storage name is used in a save workspace operation. Hence this method can be useful to avoid overwriting the workspace when saving it, for example when it was loaded from a jar file.- See Also:
-
canEncodeReference
Returns true if the given aObject can be encoded.- Parameters:
aObject
- The object to encode.aParent
- The parent of the object to encode. The parent will often be null, or for example when a domain objects needs to be saved (e.g. a polyline), the parent will normally be theILcdModel
that contains the domain object. The exact value of the parent is defined by theALcyWorkspaceObjectCodec
that will encode the object. Please check the javadoc of the addon responsible for the object to encode or refer to the Lucy Developer Guide for more information.- Returns:
- True if aObject can be encoded, false otherwise.
-
canEncodeReference
Functionally equivalent tocanEncodeReference(aObject, null)
.- See Also:
-
encodeReference
public String encodeReference(Object aObject, Object aParent) throws IOException, TLcyWorkspaceAbortedException Encodes the given object. A uniqueString
for the object is returned. TheString
is unique for one object instance and within one workspace. This means that when the same object instance is encoded multiple times, the sameString
will be returned. When decoding, thisString
can be passed todecodeReference(String)
to restore the object. IfcanEncodeReference(Object, Object)
with the same parameters returnsfalse
, this method will returnnull
.- Parameters:
aObject
- The object to encode.aParent
- The parent of the object to encode. It must be possible to encode this parent too. So eithercanEncodeReference( aParent )
must returntrue
, or if encoding the parent requires another parent, the parent must have been encoded already. The parent will often be null, or for example when a domain objects needs to be saved (e.g. a polyline), the parent will normally be theILcdModel
that contains the domain object. The exact value of the parent is defined by theALcyWorkspaceObjectCodec
that will encode the object. Please check the javadoc of the addon responsible for the object to encode or refer to the Lucy Developer Guide for more information.- Returns:
- A
String
representing the object. The returned ObjectReferenceUID is unique for one object instance and within one workspace. Returnsnull
if aObject isnull
. - Throws:
IOException
- In case of fatal IO failure.TLcyWorkspaceAbortedException
- In case the operation is aborted, e.g. because the user canceled it.
-
encodeReference
Functionally equivalent toencodeReference(aObject, null)
.- Throws:
IOException
-
encodeObject
protected void encodeObject(Object aObject, Object aParent, ALcyWorkspaceObjectCodec aCodec, OutputStream aOut) throws IOException Called when an object needs to be encoded in the current workspace. The default implementation simply calls the given codec's encodeObject method. You can override the method if you want to be notified of all the object codecs that are used during workspace encoding.- Parameters:
aObject
- the object to encodeaParent
- The parent of the object to encode (e.g. the ILcdModel of a domain object), or null if there is no parent. The type and value of the parent is defined by the codec.aCodec
- the codec delegate that can encode the given objectaOut
- the output stream to encode to- Throws:
IOException
- Since:
- 2022.1
-
decodeReference
public Object decodeReference(String aObjectReferenceUID) throws IOException, TLcyWorkspaceAbortedException Decodes the given object reference (aObjectReferenceUID) into an actualObject
. The given aObjectReferenceUID must be a string returned byencodeReference(Object)
during the encoding process. One cannot assume that because encoding the reference succeeded, decoding the same reference will work too. The given UID cannot be resolved if itsALcyWorkspaceObjectCodec
is not available. This can for example happen when an object was encoded by the codec of the addon the object belongs too, but when - in a next Lucy session - the addon is no longer loaded. Such an object could for example be a shp model decoded by theTLcyDefaultDecodersAddOn
. In such a case, null will be returned.- Parameters:
aObjectReferenceUID
- The object reference to decode.- Returns:
Null
in case the UID could not be decoded, or if the given aObjectReferenceUID isnull
. The decoded object otherwise.- Throws:
IOException
- In case of fatal IO failure.TLcyWorkspaceAbortedException
- In case the operation is aborted, e.g. because the user canceled it.
-
encodePath
Encodes an (absolute) path (e.g. a directory or a filename) into a String. Subclasses can use this e.g. to store paths relative to the location of the workspace file. The default implementation simply returns the givenaPath
.- Parameters:
aPath
- The path to encode.- Returns:
- The encoded path.
-
decodePath
Decodes aString
returned byencodePath(String)
into the original path name. Subclasses can use this e.g. to store paths relative to the location of the workspace file. The default implementation simply returns the givenaPath
.- Parameters:
aPath
- The path to decode.- Returns:
- The decoded path.
-
getParentComponent
Returns the parent component.- Returns:
- the parent component.
- See Also:
-
setParentComponent
Sets the parent component. This parent component can be used to e.g. show dialogs during the decoding/encoding process.- Parameters:
aParentComponent
- The parent component.- See Also:
-
canDecodeWorkspace
Returns true if the given aSourceName can be decoded.- Parameters:
aSourceName
- The source name to check.- Returns:
- true if the given aSourceName can be decoded.
-
canDecodeWorkspace
Returns true if the given source name can be decoded, false otherwise. The second argument of the method is a list of strings which can be used to pass a description to the caller of this method.
For example when a workspace cannot be decoded for a certain reason, a description of that reason can be added to the list of strings.- Parameters:
aSourceName
- The source name to checkaReasonsSFCT
- A side-effect parameter to which this method may add reasons on why it returnedtrue
orfalse
- Returns:
true
if the given source name can be decoded,false
otherwise- Since:
- 2015.1
-
canEncodeWorkspace
Returns true if the workspace can be encoded to the givenaDestinationName
- Parameters:
aDestinationName
- The destination name to check.- Returns:
- true if the workspace can be encoded to the given
aDestinationName
-
retrieveOutputStream
Returns anOutputStream
for the given aUID. The returnedOutputStream
should be a new instance for every UID, as several streams might be open at the same time, and data can be written to any of those open streams. This method is used several times during workspace endoding: the stream for every UID represents one little part of the workspace. During decoding,retrieveInputStream(aUID)
must return anInputStream
that refers to the same data block as the one written to the correspondingOutputStream
. Subclasses can implement this method in various ways: they can store every stream in a separate file, they can store all streams in one single file, they can store the streams in a database, ...- Parameters:
aUID
- The identifier to retrieve anOutputStream
for.- Returns:
- The
OutputStream
- Throws:
IOException
- In case of fatal IO failure.- See Also:
-
retrieveInputStream
Returns anInputStream
for the given aUID. The returnedInputStream
should be a new instance for every UID, as several streams might be open at the same time, and data can be read from any of those open streams. It is assumed that every stream can be read until end of stream. This method is used several times during workspace dedoding: the stream for every UID represents one little part of the workspace. This method must return anInputStream
referring to the same data block as the data that was written to theOutputStream
created byretrieveOutputStream(String)
for the same aUID. Subclasses can implement this method in various ways: they can retrieve every stream from a separate file, they can retrieve all streams from one single file, they can retrieve the streams from a database, ...- Parameters:
aUID
- The identifier to retrieve anOutputStream
for.- Returns:
- The
OutputStream
- Throws:
IOException
- In case of fatal IO failure.- See Also:
-