P
- the type of AbstractFolder
.I
- the type of TopLevelItem
within the folder.public abstract class ChildNameGenerator<P extends AbstractFolder<I>,I extends TopLevelItem> extends Object
ComputedFolder
to break the association between the directory names on disk
that are used to store its items and the Item.getName()
which is used to create the URL of the item.
NOTE: if you need to implement this functionality, you need to ensure that users cannot rename
items within the ComputedFolder
as renaming is not supported when using a ChildNameGenerator
.
Challenges:
itemNameFromItem(AbstractFolder, TopLevelItem)
and
dirNameFromItem(AbstractFolder, TopLevelItem)
regarding the constraints on how to name thingsPersistenceRoot.getRootDir()
during construction (those are bold evil item types
that leak side-effects, you should fix them if you find them). While you wait for them to be fixed you will need
to work-around the issue by ensuring that you call beforeCreateItem(AbstractFolder, String, String)
passing the Item.getName()
you want the item to have and the ideal unmangled name
before you call new ChildItemType(parent,name)
and then call
afterItemCreated(Trace)
when the constructor has returned. Then insure that your
itemNameFromItem(AbstractFolder, TopLevelItem)
and dirNameFromItem(AbstractFolder, TopLevelItem)
fall back to idealNameFromItem(AbstractFolder, TopLevelItem)
when the magic property they are looking
for is missing.ComputedFolder
using this ChildNameGenerator
will be attaching into the Item
the
actual name, typically via a JobProperty
or Action
(beware TransientActionFactory
implementations may want to invoke PersistenceRoot.getRootDir()
which will trigger a stack overflow though, so
safer to stick with the JobProperty
or equivalent). The
itemNameFromItem(AbstractFolder, TopLevelItem)
method's task is to find the stored name
and return the name stored within or null
if that information is missing (in which case
itemNameFromLegacy(AbstractFolder, String)
will be called to try and infer the name from the
disk name that the Item
is being loaded from.
A similar relation exists for the dirNameFromItem(AbstractFolder, TopLevelItem)
and
dirNameFromLegacy(AbstractFolder, String)
methods.Modifier and Type | Class and Description |
---|---|
static class |
ChildNameGenerator.Trace
Traces the creation of a new
Item in a folder. |
Modifier and Type | Field and Description |
---|---|
static String |
CHILD_NAME_FILE
The name of the file that contains the actual name of the child item.
|
Constructor and Description |
---|
ChildNameGenerator() |
Modifier and Type | Method and Description |
---|---|
static ChildNameGenerator.Trace |
beforeCreateItem(AbstractFolder<?> project,
String itemName,
String idealName)
Work-around helper method to "fix"
Item constructors that have on-disk side-effects and therefore
need PersistenceRoot.getRootDir() to work during the constructor. |
abstract String |
dirNameFromItem(P parent,
I item)
Infers the directory name in which the
Item instance itself should be stored. |
abstract String |
dirNameFromLegacy(P parent,
String legacyDirName)
dirNameFromItem(AbstractFolder, TopLevelItem) could not help, we are loading the item for the first
time since the ChildNameGenerator was enabled for the parent folder type, this method's mission is
to pretend the legacyDirName is the "mostly correct" name and turn this into the filesystem safe
mangled equivalent name to use going forward. |
protected String |
idealNameFromItem(P parent,
I item)
Looks up the
Item to see if we stored the ideal name before invoking the constructor that is having
on-disk side-effects before the object has escaped beforeCreateItem(AbstractFolder, String, String) |
abstract String |
itemNameFromItem(P parent,
I item)
Infers the
Item.getName() from the Item instance itself. |
abstract String |
itemNameFromLegacy(P parent,
String legacyDirName)
itemNameFromItem(AbstractFolder, TopLevelItem) could not help, we are loading the item for the first
time since the ChildNameGenerator was enabled for the parent folder type, this method's mission is
to pretend the legacyDirName is the "mostly correct" name and turn this into the actual name. |
abstract void |
recordLegacyName(P parent,
I item,
String legacyDirName)
Record the ideal name inferred in the item when it was missing and has been inferred from the legacy directory
name.
|
public static final String CHILD_NAME_FILE
If there is nothing else to go on, this file will be used in preference to the child directory name, but as it
is too easy for users to mistakenly think changing the contents of the file will rename the child (which could
cause data loss for the computed folder's child) it is better for implementations to store the definitive
ideal name in a JobProperty
, Action
or equivalent that is attached directly to the Item
.
@Nonnull public static final ChildNameGenerator.Trace beforeCreateItem(@Nonnull AbstractFolder<?> project, @Nonnull String itemName, @Nonnull String idealName)
Item
constructors that have on-disk side-effects and therefore
need PersistenceRoot.getRootDir()
to work during the constructor.project
- the AbstractFolder
.itemName
- the name that will be returned by Item.getName()
when the item is constructed. This is
the second parameter of AbstractItem(ItemGroup, String)
. This one would be
the one with URL path segment escaping.idealName
- the original name before whatever URL path segment escaping you appliedChildNameGenerator.Trace
to keep track of when we can remove the memory of the creation process. Please
ChildNameGenerator.Trace.close()
the trace after the item is created.@CheckForNull protected final String idealNameFromItem(@Nonnull P parent, @Nonnull I item)
Item
to see if we stored the ideal name before invoking the constructor that is having
on-disk side-effects before the object has escaped beforeCreateItem(AbstractFolder, String, String)
parent
- the parent within which the item is being created.item
- the partially created item.@CheckForNull public abstract String itemNameFromItem(@Nonnull P parent, @Nonnull I item)
Item.getName()
from the Item
instance itself.
Challenges include:
"/" / "?" / "#" / "[" / "]" / "\"
as these could end up modifying the effective URL"" / "." / ".."
as these could end creating broken effective URLsparent
- the parent within which the item is being loaded.item
- the partially loaded item (take care what methods you call, the item will not have a reference to
its parent).@CheckForNull public abstract String dirNameFromItem(@Nonnull P parent, @Nonnull I item)
Item
instance itself should be stored.
Challenges include:
A-Za-z0-9_.-
AUX, COM1, COM2, ..., COM9, CON, LPT1, LPT2, ..., LPT9, NUL, PRN
plus all case variations of these
names plus the variants where a single .
is appended, you need to map those to something elseparent
- the parent within which the item is being loaded.item
- the partially loaded item (take care what methods you call, the item will not have a reference to
its parent).@Nonnull public abstract String itemNameFromLegacy(@Nonnull P parent, @Nonnull String legacyDirName)
itemNameFromItem(AbstractFolder, TopLevelItem)
could not help, we are loading the item for the first
time since the ChildNameGenerator
was enabled for the parent folder type, this method's mission is
to pretend the legacyDirName
is the "mostly correct" name and turn this into the actual name.
Challenges include:
Util.rawEncode(String)
so you may need to
decode it first"/" / "?" / "#" / "[" / "]" / "\"
as these could end up modifying the effective URL"" / "." / ".."
as these could end creating broken effective URLsparent
- the parent within which the item is being loaded.legacyDirName
- the directory name that we are loading an item from.@Nonnull public abstract String dirNameFromLegacy(@Nonnull P parent, @Nonnull String legacyDirName)
dirNameFromItem(AbstractFolder, TopLevelItem)
could not help, we are loading the item for the first
time since the ChildNameGenerator
was enabled for the parent folder type, this method's mission is
to pretend the legacyDirName
is the "mostly correct" name and turn this into the filesystem safe
mangled equivalent name to use going forward.
Challenges include:
A-Za-z0-9_.-
AUX, COM1, COM2, ..., COM9, CON, LPT1, LPT2, ..., LPT9, NUL, PRN
plus all case variations of these
names plus the variants where a single .
is appended, you need to map those to something elseparent
- the parent within which the item is being loaded.legacyDirName
- the directory name that we are loading an item from.public abstract void recordLegacyName(P parent, I item, String legacyDirName) throws IOException
parent
- the parent.item
- the item.legacyDirName
- the name of the directory that the item was loaded from.IOException
- if the ideal name could not be attached to the item.Copyright © 2016–2020. All rights reserved.