This is an automated email from the ASF dual-hosted git repository. tballison pushed a commit to branch TIKA-4816-metadata-key-api in repository https://gitbox.apache.org/repos/asf/tika.git
commit bb60edb384a9b0ce2ad41b7649e8af0d5ee29a70 Author: tallison <[email protected]> AuthorDate: Tue Aug 11 13:40:27 2026 -0400 TIKA-4816 metadata-key stage 3: KeyPrefix rename + constructor validation + typed minting factories --- .skills/metadata-schema.md | 6 +- docs/modules/ROOT/pages/developers/index.adoc | 2 +- .../ROOT/pages/developers/metadata-keys.adoc | 6 +- .../main/java/org/apache/tika/metadata/DWG.java | 4 +- .../main/java/org/apache/tika/metadata/HTML.java | 2 +- .../java/org/apache/tika/metadata/KeyPrefix.java | 172 +++++++++++++++++++ .../main/java/org/apache/tika/metadata/MAPI.java | 2 +- .../java/org/apache/tika/metadata/Message.java | 2 +- .../main/java/org/apache/tika/metadata/Office.java | 2 +- .../main/java/org/apache/tika/metadata/PDF.java | 4 +- .../apache/tika/metadata/PassthroughPrefix.java | 79 --------- .../java/org/apache/tika/metadata/RTFMetadata.java | 2 +- .../org/apache/tika/metadata/KeyPrefixTest.java | 182 +++++++++++++++++++++ tika-metadata-schema/README.md | 6 +- tika-metadata-schema/regen.sh | 8 +- .../tika/metadata/schema/SchemaGenerator.java | 12 +- .../tika/metadata/schema/MetadataCoverageTest.java | 4 +- .../tika/metadata/schema/MetadataSchemaTest.java | 4 +- .../apache/tika/parser/envi/EnviHeaderParser.java | 6 +- .../org/apache/tika/parser/grib/GribParser.java | 6 +- .../apache/tika/parser/netcdf/NetCDFParser.java | 6 +- .../tika/parser/ctakes/CTAKESContentHandler.java | 6 +- .../tika/parser/journal/GrobidRESTParser.java | 6 +- .../apache/tika/parser/ner/NamedEntityParser.java | 6 +- .../tika/parser/iwork/NumbersContentHandler.java | 6 +- .../parser/iwork/iwana/IWork13PackageParser.java | 6 +- .../org/apache/tika/parser/ogg/OggAudioParser.java | 6 +- .../org/apache/tika/parser/video/FLVParser.java | 6 +- .../java/org/apache/tika/parser/dwg/DWGParser.java | 6 +- .../tika/parser/image/ImageMetadataExtractor.java | 10 +- .../org/apache/tika/parser/mbox/MboxParser.java | 6 +- .../tika/parser/microsoft/JackcessParser.java | 14 +- .../org/apache/tika/parser/warc/WARCParser.java | 10 +- .../org/apache/tika/parser/xmp/XmpExtractor.java | 4 +- 34 files changed, 442 insertions(+), 167 deletions(-) diff --git a/.skills/metadata-schema.md b/.skills/metadata-schema.md index da51bf1fdb..a31c02cc74 100644 --- a/.skills/metadata-schema.md +++ b/.skills/metadata-schema.md @@ -9,19 +9,19 @@ this covers conventions, regeneration, and the traps. Under `tika-metadata-schema/src/main/resources/org/apache/tika/metadata/`: - `metadata-keys.json` — closed set: every `Property` constant + the synthesized `tk:digest:*` cross-product. -- `metadata-open-namespaces.json` — `PassthroughPrefix` prefixes for runtime-minted names (`html:`, `message:raw-header:`, `mdb-prop:`). +- `metadata-open-namespaces.json` — `KeyPrefix` prefixes for runtime-minted names (`html:`, `message:raw-header:`, `mdb-prop:`). - `metadata-key-fields.json` — TIKA-4797 `{class, field, key}` table for field-identity migration. Committed on purpose: they are the reviewable audit trail of the key space (a rename or a dropped key shows up as a diff). Don't switch to build-time-only generation — that loses the review signal. -## Regenerate (after adding/changing a Property or PassthroughPrefix) +## Regenerate (after adding/changing a Property or KeyPrefix) ```bash tika-metadata-schema/regen.sh ``` -This does the full sequence in one shot: `-am install` so newly added Property/PassthroughPrefix +This does the full sequence in one shot: `-am install` so newly added Property/KeyPrefix classes are on the scan classpath, regenerate all three registries via the forked-exec profile, print a before/after key-count check (catches an incomplete classpath scan), `git diff --stat` the registries, then run the gate tests. Flags: `--skip-install` (only safe if nothing outside diff --git a/docs/modules/ROOT/pages/developers/index.adoc b/docs/modules/ROOT/pages/developers/index.adoc index ac1ef574be..95701969c6 100644 --- a/docs/modules/ROOT/pages/developers/index.adoc +++ b/docs/modules/ROOT/pages/developers/index.adoc @@ -22,7 +22,7 @@ with custom parsers, detectors, and other components. * xref:developers/serialization.adoc[Serialization and Configuration] - JSON configuration, @TikaComponent annotation, and creating custom components -* xref:developers/metadata-keys.adoc[Adding a Metadata Key] - the Property/PassthroughPrefix +* xref:developers/metadata-keys.adoc[Adding a Metadata Key] - the Property/KeyPrefix registry, naming conventions, and regenerating the schema == Coming Soon diff --git a/docs/modules/ROOT/pages/developers/metadata-keys.adoc b/docs/modules/ROOT/pages/developers/metadata-keys.adoc index 7d5deeb4f7..71ca570b70 100644 --- a/docs/modules/ROOT/pages/developers/metadata-keys.adoc +++ b/docs/modules/ROOT/pages/developers/metadata-keys.adoc @@ -16,7 +16,7 @@ = Adding a Metadata Key Every metadata key Tika can emit is a `Property` constant (or, for runtime-minted names like scraped -HTML `<meta>` tags, a `PassthroughPrefix`) — there are no bare `String` keys. That closed/open key +HTML `<meta>` tags, a `KeyPrefix`) — there are no bare `String` keys. That closed/open key space is tracked in a generated, build-gated registry, so adding a key involves one extra step beyond writing the Java. @@ -40,10 +40,10 @@ Naming conventions (frozen for 4.0): The registry — three JSON files under `tika-metadata-schema/src/main/resources/`, listing every declared key, every open-namespace prefix, and a field-provenance table — is generated from the live -`Property`/`PassthroughPrefix` declarations, never hand-edited. A committed copy is the reviewable +`Property`/`KeyPrefix` declarations, never hand-edited. A committed copy is the reviewable audit trail (a rename or dropped key shows up as a diff), and CI fails if it's stale. -Run this after adding, renaming, or removing a `Property` or `PassthroughPrefix`: +Run this after adding, renaming, or removing a `Property` or `KeyPrefix`: [source,bash] ---- diff --git a/tika-core/src/main/java/org/apache/tika/metadata/DWG.java b/tika-core/src/main/java/org/apache/tika/metadata/DWG.java index 67a51a8732..a2b70918ff 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/DWG.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/DWG.java @@ -23,8 +23,8 @@ public interface DWG { String DWG_PREFIX = "dwg" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - PassthroughPrefix RAW_FIELD = - PassthroughPrefix.file(DWG_PREFIX, "DWGRead JSON header/summary field names"); + KeyPrefix RAW_FIELD = + KeyPrefix.file(DWG_PREFIX, "DWGRead JSON header/summary field names"); Property APPLICATION_NAME = Property.externalText(DWG_PREFIX + "application-name"); diff --git a/tika-core/src/main/java/org/apache/tika/metadata/HTML.java b/tika-core/src/main/java/org/apache/tika/metadata/HTML.java index a26c979479..97c45da5e3 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/HTML.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/HTML.java @@ -19,7 +19,7 @@ package org.apache.tika.metadata; public interface HTML { String PREFIX_HTML_META = "html" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - PassthroughPrefix SCRAPED_META = PassthroughPrefix.file(PREFIX_HTML_META, + KeyPrefix SCRAPED_META = KeyPrefix.file(PREFIX_HTML_META, "scraped <meta>/http-equiv/OpenGraph names not mapped to a Property"); diff --git a/tika-core/src/main/java/org/apache/tika/metadata/KeyPrefix.java b/tika-core/src/main/java/org/apache/tika/metadata/KeyPrefix.java new file mode 100644 index 0000000000..bf244164c6 --- /dev/null +++ b/tika-core/src/main/java/org/apache/tika/metadata/KeyPrefix.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.metadata; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tika.metadata.Property.PropertyType; +import org.apache.tika.metadata.Property.ValueType; + +/** + * A Tika-owned prefix under which keys are passed through from the source: the prefix is fixed, but + * each key name comes verbatim from the document or tool, so keys are unbounded and can't be + * {@link Property} constants. Declaring one self-registers it, so the open set is enumerable (as + * {@link Property} makes the closed set) and lintable: a String write is legitimate iff its key is a + * registered {@link Property} or its prefix is a registered {@code KeyPrefix}. + * + * <p><strong>{@code KeyPrefix} instances are declaration-time constants.</strong> Declare one as a + * {@code static final} field, the same way a curated {@link Property} constant is declared — never + * construct one from document-derived text, and never construct one per-parse: the registry is + * static and unbounded per-parse construction grows it forever (and now also throws, see below). + * + * @since Apache Tika 4.0.0 + */ +public final class KeyPrefix { + + public enum Provenance { FILE, TOOL } + + /** Delimiters accepted at the end of a prefix; kept intentionally loose (some declarations + * predate a single convention) — see {@code ReservedNamespaces} for the reserved-name check. */ + private static final char[] TRAILING_DELIMITERS = {':', '.', '-', '_'}; + + private static final Map<String, KeyPrefix> REGISTRY = new ConcurrentHashMap<>(); + + private final String prefix; + private final Provenance provenance; + private final String description; + + private KeyPrefix(String prefix, Provenance provenance, String description) { + if (prefix == null || prefix.isEmpty()) { + throw new IllegalArgumentException("KeyPrefix prefix must not be null or empty"); + } + if (ReservedNamespaces.isTikaNative(prefix)) { + throw new IllegalArgumentException("'" + prefix + "' is in the reserved Tika-native " + + "namespace (tk:/X-TIKA:); it cannot be a KeyPrefix"); + } + if (!hasTrailingDelimiter(prefix)) { + throw new IllegalArgumentException("'" + prefix + "' must end with one of " + + Arrays.toString(TRAILING_DELIMITERS)); + } + this.prefix = prefix; + this.provenance = provenance; + this.description = description; + KeyPrefix incumbent = REGISTRY.putIfAbsent(prefix, this); + if (incumbent != null) { + throw new IllegalStateException( + "KeyPrefix '" + prefix + "' is already registered; KeyPrefix instances are " + + "declaration-time constants and must be constructed exactly once " + + "(never from document-derived text, never per-parse)"); + } + } + + private static boolean hasTrailingDelimiter(String prefix) { + char last = prefix.charAt(prefix.length() - 1); + for (char d : TRAILING_DELIMITERS) { + if (d == last) { + return true; + } + } + return false; + } + + public static KeyPrefix file(String prefix, String description) { + return new KeyPrefix(prefix, Provenance.FILE, description); + } + + public static KeyPrefix tool(String prefix, String description) { + return new KeyPrefix(prefix, Provenance.TOOL, description); + } + + /** The full key for a source-derived {@code suffix}. */ + public String key(String suffix) { + return prefix + suffix; + } + + public String prefix() { + return prefix; + } + + public Provenance provenance() { + return provenance; + } + + public String description() { + return description; + } + + /** Declared prefixes, from loaded classes only. */ + public static Collection<KeyPrefix> registered() { + return Collections.unmodifiableCollection(REGISTRY.values()); + } + + // ---- Typed minting factories ----------------------------------------------------- + // Each mints an UNREGISTERED Property (Property.mintUnregistered) named prefix + name, + // shaped like the corresponding external* Property factory. Mint per call for doc-derived + // names: minted Properties are cheap, unregistered value objects, GC'd with the parse. + // A bounded, known vocabulary belongs in a curated Property constant instead (that IS the + // cache, with registry/CI coverage) — never build a name-keyed static cache here, that + // recreates the registry-growth leak this design avoids. + + private static void requireNonEmptyName(String name) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("KeyPrefix-minted Property name must not be null " + + "or empty"); + } + } + + /** Mints an unregistered SIMPLE/TEXT Property, like {@link Property#externalText}. */ + public Property text(String name) { + requireNonEmptyName(name); + return Property.mintUnregistered(key(name), false, PropertyType.SIMPLE, ValueType.TEXT, null); + } + + /** Mints an unregistered BAG/TEXT Property, like {@link Property#externalTextBag}. */ + public Property textBag(String name) { + requireNonEmptyName(name); + return Property.mintUnregistered(key(name), false, PropertyType.BAG, ValueType.TEXT, null); + } + + /** Mints an unregistered SIMPLE/DATE Property, like {@link Property#externalDate}. */ + public Property date(String name) { + requireNonEmptyName(name); + return Property.mintUnregistered(key(name), false, PropertyType.SIMPLE, ValueType.DATE, null); + } + + /** Mints an unregistered SIMPLE/INTEGER Property, like {@link Property#externalInteger}. */ + public Property integer(String name) { + requireNonEmptyName(name); + return Property.mintUnregistered(key(name), false, PropertyType.SIMPLE, ValueType.INTEGER, + null); + } + + /** Mints an unregistered SIMPLE/REAL Property, like {@link Property#externalReal}. */ + public Property real(String name) { + requireNonEmptyName(name); + return Property.mintUnregistered(key(name), false, PropertyType.SIMPLE, ValueType.REAL, null); + } + + /** Mints an unregistered SIMPLE/BOOLEAN Property, like {@link Property#externalBoolean}. */ + public Property bool(String name) { + requireNonEmptyName(name); + return Property.mintUnregistered(key(name), false, PropertyType.SIMPLE, ValueType.BOOLEAN, + null); + } +} diff --git a/tika-core/src/main/java/org/apache/tika/metadata/MAPI.java b/tika-core/src/main/java/org/apache/tika/metadata/MAPI.java index 74657ce85b..5b9b940913 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/MAPI.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/MAPI.java @@ -27,7 +27,7 @@ public interface MAPI { String PREFIX_MAPI_META = "mapi" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; String PREFIX_MAPI_ATTACH_META = "mapi:attach" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; String PREFIX_MAPI_PROPERTY = PREFIX_MAPI_META + "property" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - PassthroughPrefix PROPERTY = PassthroughPrefix.file(PREFIX_MAPI_PROPERTY, "MAPI named properties"); + KeyPrefix PROPERTY = KeyPrefix.file(PREFIX_MAPI_PROPERTY, "MAPI named properties"); /** * MAPI message class. What type of .msg/MAPI file is it? diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Message.java b/tika-core/src/main/java/org/apache/tika/metadata/Message.java index cf711eeec8..e069a396a6 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/Message.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/Message.java @@ -29,7 +29,7 @@ public interface Message { String MESSAGE_RAW_HEADER_PREFIX = MESSAGE_PREFIX + "raw-header" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - PassthroughPrefix RAW_HEADER = PassthroughPrefix.file(MESSAGE_RAW_HEADER_PREFIX, + KeyPrefix RAW_HEADER = KeyPrefix.file(MESSAGE_RAW_HEADER_PREFIX, "RFC822 / Outlook raw email header names"); Property MESSAGE_RECIPIENT_ADDRESS = diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Office.java b/tika-core/src/main/java/org/apache/tika/metadata/Office.java index 2a348f45d9..f2d7ccc686 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/Office.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/Office.java @@ -37,7 +37,7 @@ public interface Office { */ String USER_DEFINED_METADATA_NAME_PREFIX = "custom:"; - PassthroughPrefix USER_DEFINED = PassthroughPrefix.file(USER_DEFINED_METADATA_NAME_PREFIX, + KeyPrefix USER_DEFINED = KeyPrefix.file(USER_DEFINED_METADATA_NAME_PREFIX, "OOXML/OLE2/ODF user-defined document properties"); diff --git a/tika-core/src/main/java/org/apache/tika/metadata/PDF.java b/tika-core/src/main/java/org/apache/tika/metadata/PDF.java index c7bda2fdf4..08f2645208 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/PDF.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/PDF.java @@ -51,8 +51,8 @@ public interface PDF { String PDF_DOC_INFO_CUSTOM_PREFIX = PDF_DOC_INFO_PREFIX + "custom" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - PassthroughPrefix DOC_INFO_CUSTOM = - PassthroughPrefix.file(PDF_DOC_INFO_CUSTOM_PREFIX, "PDF Info-dict custom keys"); + KeyPrefix DOC_INFO_CUSTOM = + KeyPrefix.file(PDF_DOC_INFO_CUSTOM_PREFIX, "PDF Info-dict custom keys"); Property DOC_INFO_CREATED = Property.internalDate(PDF_DOC_INFO_PREFIX + "created"); diff --git a/tika-core/src/main/java/org/apache/tika/metadata/PassthroughPrefix.java b/tika-core/src/main/java/org/apache/tika/metadata/PassthroughPrefix.java deleted file mode 100644 index ea17d3b555..0000000000 --- a/tika-core/src/main/java/org/apache/tika/metadata/PassthroughPrefix.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tika.metadata; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * A Tika-owned prefix under which keys are passed through from the source: the prefix is fixed, but - * each key name comes verbatim from the document or tool, so keys are unbounded and can't be - * {@link Property} constants. Declaring one self-registers it, so the open set is enumerable (as - * {@link Property} makes the closed set) and lintable: a String write is legitimate iff its key is a - * registered {@link Property} or its prefix is a registered {@code PassthroughPrefix}. - * - * @since Apache Tika 4.0.0 - */ -public final class PassthroughPrefix { - - public enum Provenance { FILE, TOOL } - - private static final Map<String, PassthroughPrefix> REGISTRY = new ConcurrentHashMap<>(); - - private final String prefix; - private final Provenance provenance; - private final String description; - - private PassthroughPrefix(String prefix, Provenance provenance, String description) { - this.prefix = prefix; - this.provenance = provenance; - this.description = description; - REGISTRY.put(prefix, this); - } - - public static PassthroughPrefix file(String prefix, String description) { - return new PassthroughPrefix(prefix, Provenance.FILE, description); - } - - public static PassthroughPrefix tool(String prefix, String description) { - return new PassthroughPrefix(prefix, Provenance.TOOL, description); - } - - /** The full key for a source-derived {@code suffix}. */ - public String key(String suffix) { - return prefix + suffix; - } - - public String prefix() { - return prefix; - } - - public Provenance provenance() { - return provenance; - } - - public String description() { - return description; - } - - /** Declared prefixes, from loaded classes only. */ - public static Collection<PassthroughPrefix> registered() { - return Collections.unmodifiableCollection(REGISTRY.values()); - } -} diff --git a/tika-core/src/main/java/org/apache/tika/metadata/RTFMetadata.java b/tika-core/src/main/java/org/apache/tika/metadata/RTFMetadata.java index 94aefbc85b..f1eb58d213 100644 --- a/tika-core/src/main/java/org/apache/tika/metadata/RTFMetadata.java +++ b/tika-core/src/main/java/org/apache/tika/metadata/RTFMetadata.java @@ -26,7 +26,7 @@ public interface RTFMetadata { String RTF_PICT_META_PREFIX = "rtf:pict:"; /** Open (file-controlled) RTF embedded-object property names built off {@link #RTF_PICT_META_PREFIX}. */ - PassthroughPrefix PICT = PassthroughPrefix.file(RTF_PICT_META_PREFIX, + KeyPrefix PICT = KeyPrefix.file(RTF_PICT_META_PREFIX, "RTF embedded picture-object property pairs (sn/sv); file-controlled names"); /** diff --git a/tika-core/src/test/java/org/apache/tika/metadata/KeyPrefixTest.java b/tika-core/src/test/java/org/apache/tika/metadata/KeyPrefixTest.java new file mode 100644 index 0000000000..25bd8e29d9 --- /dev/null +++ b/tika-core/src/test/java/org/apache/tika/metadata/KeyPrefixTest.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.metadata; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +import org.apache.tika.metadata.Property.PropertyType; +import org.apache.tika.metadata.Property.ValueType; + +/** + * Stage 3: the {@code PassthroughPrefix} -> {@code KeyPrefix} rename, constructor validation, + * and the typed unregistered-Property minting factories. + */ +public class KeyPrefixTest { + + // Every registered prefix is a unique, unrepeatable static registration -- give each test + // its own prefix (nanoTime-suffixed, following PropertyReservedNameTest's convention) so + // tests never collide with each other or with real parser-declared prefixes. + private static String uniquePrefix(String label) { + return "keyprefix-test-" + label + "-" + System.nanoTime() + ":"; + } + + @Test + public void testRejectsNullPrefix() { + assertThrows(IllegalArgumentException.class, () -> KeyPrefix.file(null, "d")); + } + + @Test + public void testRejectsEmptyPrefix() { + assertThrows(IllegalArgumentException.class, () -> KeyPrefix.file("", "d")); + } + + @Test + public void testRejectsReservedTkPrefix() { + assertThrows(IllegalArgumentException.class, () -> KeyPrefix.file("tk:", "d")); + } + + @Test + public void testRejectsReservedLegacyXTikaPrefix() { + assertThrows(IllegalArgumentException.class, () -> KeyPrefix.file("X-TIKA:", "d")); + } + + @Test + public void testRejectsMissingTrailingDelimiter() { + String prefix = "keyprefix-test-no-delim-" + System.nanoTime(); + assertThrows(IllegalArgumentException.class, () -> KeyPrefix.file(prefix, "d")); + } + + @Test + public void testAcceptsAllCurrentlyUsedTrailingDelimiters() { + // ':' '.' '-' '_' -- the population enumerated pre-implementation (netcdf: envi. + // grobid:header_ MboxParser- etc). A later stage normalizes these to ':'; stage 3 must + // not break the still-live population. + for (char delim : new char[]{':', '.', '-', '_'}) { + String prefix = uniquePrefix("delim-" + delim) + delim; + KeyPrefix.file(prefix, "d"); // must not throw + } + } + + @Test + public void testDuplicateRegistrationThrows() { + String prefix = uniquePrefix("dup"); + KeyPrefix.file(prefix, "first"); + assertThrows(IllegalStateException.class, () -> KeyPrefix.tool(prefix, "second")); + } + + @Test + public void testKeyUnchanged() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("key"), "d"); + assertEquals(kp.prefix() + "suffix", kp.key("suffix")); + } + + @Test + public void testFileProvenancePreserved() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("prov-file"), "d"); + assertEquals(KeyPrefix.Provenance.FILE, kp.provenance()); + } + + @Test + public void testToolProvenancePreserved() { + KeyPrefix kp = KeyPrefix.tool(uniquePrefix("prov-tool"), "d"); + assertEquals(KeyPrefix.Provenance.TOOL, kp.provenance()); + } + + @Test + public void testTextFactoryShape() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("text"), "d"); + Property p = kp.text("name"); + assertEquals(kp.prefix() + "name", p.getName()); + assertEquals(PropertyType.SIMPLE, p.getPropertyType()); + assertEquals(ValueType.TEXT, p.getValueType()); + assertNull(Property.get(p.getName()), "minted Property must not register"); + } + + @Test + public void testTextBagFactoryShape() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("textbag"), "d"); + Property p = kp.textBag("name"); + assertEquals(kp.prefix() + "name", p.getName()); + assertEquals(PropertyType.BAG, p.getPropertyType()); + assertEquals(ValueType.TEXT, p.getValueType()); + assertNull(Property.get(p.getName())); + } + + @Test + public void testDateFactoryShape() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("date"), "d"); + Property p = kp.date("name"); + assertEquals(kp.prefix() + "name", p.getName()); + assertEquals(PropertyType.SIMPLE, p.getPropertyType()); + assertEquals(ValueType.DATE, p.getValueType()); + assertNull(Property.get(p.getName())); + } + + @Test + public void testIntegerFactoryShape() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("integer"), "d"); + Property p = kp.integer("name"); + assertEquals(kp.prefix() + "name", p.getName()); + assertEquals(PropertyType.SIMPLE, p.getPropertyType()); + assertEquals(ValueType.INTEGER, p.getValueType()); + assertNull(Property.get(p.getName())); + } + + @Test + public void testRealFactoryShape() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("real"), "d"); + Property p = kp.real("name"); + assertEquals(kp.prefix() + "name", p.getName()); + assertEquals(PropertyType.SIMPLE, p.getPropertyType()); + assertEquals(ValueType.REAL, p.getValueType()); + assertNull(Property.get(p.getName())); + } + + @Test + public void testBoolFactoryShape() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("bool"), "d"); + Property p = kp.bool("name"); + assertEquals(kp.prefix() + "name", p.getName()); + assertEquals(PropertyType.SIMPLE, p.getPropertyType()); + assertEquals(ValueType.BOOLEAN, p.getValueType()); + assertNull(Property.get(p.getName())); + } + + @Test + public void testFactoriesRejectEmptyName() { + KeyPrefix kp = KeyPrefix.file(uniquePrefix("empty-name"), "d"); + assertThrows(IllegalArgumentException.class, () -> kp.text("")); + assertThrows(IllegalArgumentException.class, () -> kp.text(null)); + assertThrows(IllegalArgumentException.class, () -> kp.textBag("")); + assertThrows(IllegalArgumentException.class, () -> kp.date("")); + assertThrows(IllegalArgumentException.class, () -> kp.integer("")); + assertThrows(IllegalArgumentException.class, () -> kp.real("")); + assertThrows(IllegalArgumentException.class, () -> kp.bool("")); + } + + @Test + public void testRegisteredIncludesDeclaredPrefix() { + String prefix = uniquePrefix("registered"); + KeyPrefix kp = KeyPrefix.file(prefix, "d"); + assertTrue(KeyPrefix.registered().contains(kp)); + } +} diff --git a/tika-metadata-schema/README.md b/tika-metadata-schema/README.md index 94968e36fa..7650ed36ca 100644 --- a/tika-metadata-schema/README.md +++ b/tika-metadata-schema/README.md @@ -36,7 +36,7 @@ declare a `Property` field, force-loads them, reads the global `Property` table, sorted JSON. `MetadataSchemaTest` regenerates in-memory and asserts it matches the committed file, so the registry can never drift from the declarations. -Regenerate after adding/changing a `Property` **or** a `PassthroughPrefix` (writes all three files): +Regenerate after adding/changing a `Property` **or** a `KeyPrefix` (writes all three files): ``` tika-metadata-schema/regen.sh ``` @@ -50,8 +50,8 @@ The **prefixes** under which parsers mint file-controlled key names at runtime `html:`, OOXML `custom:`, email `Message:Raw-Header:`, Access `MDB_PROP:`, Vorbis comments, FLV attributes, unmapped image/XMP tags, …). Each record: `{ prefix, provenance, description }`. -**Generated from the `PassthroughPrefix` declarations, never hand-edited.** Every such prefix is a -registered `PassthroughPrefix` constant; `SchemaGenerator` reads that registry the same way it reads +**Generated from the `KeyPrefix` declarations, never hand-edited.** Every such prefix is a +registered `KeyPrefix` constant; `SchemaGenerator` reads that registry the same way it reads the `Property` table, and `MetadataSchemaTest` gates it identically. Adding a passthrough prefix in a parser and forgetting to regenerate fails the build. diff --git a/tika-metadata-schema/regen.sh b/tika-metadata-schema/regen.sh index 4d20fa7f45..1874468e57 100755 --- a/tika-metadata-schema/regen.sh +++ b/tika-metadata-schema/regen.sh @@ -2,7 +2,7 @@ # # Regenerates and validates the metadata key registry (tika-metadata-schema). # -# Run this after adding, renaming, or removing a Property or PassthroughPrefix +# Run this after adding, renaming, or removing a Property or KeyPrefix # constant anywhere in tika-core or the standard parser bundle. It replaces the # multi-step manual sequence in .skills/metadata-schema.md with one command: # install the dependency modules, regenerate the three registry files, sanity @@ -12,7 +12,7 @@ # tika-metadata-schema/regen.sh [--skip-install] [--skip-tests] # # --skip-install skip the -am install step (only safe if no Property/ -# PassthroughPrefix classes outside tika-metadata-schema +# KeyPrefix classes outside tika-metadata-schema # changed since the last install) # --skip-tests skip the final gate-test run, for a faster inner loop # @@ -53,7 +53,7 @@ REGISTRY_FILES=( if [ "$SKIP_INSTALL" -eq 0 ]; then echo "==> Installing tika-metadata-schema + its dependency modules (tika-core, standard parsers)" - echo " so newly added Property/PassthroughPrefix classes are on the scan classpath." + echo " so newly added Property/KeyPrefix classes are on the scan classpath." echo " (skip with --skip-install if you already did this)" ./mvnw -Pfast -DskipTests -pl tika-metadata-schema -am install "$MVN_REPO_OPT" fi @@ -92,4 +92,4 @@ if [ "$SKIP_TESTS" -eq 0 ]; then ./mvnw -pl tika-metadata-schema test "$MVN_REPO_OPT" fi -echo "==> Done. Review the diff above, then commit the Property/PassthroughPrefix change and the regenerated JSON together." +echo "==> Done. Review the diff above, then commit the Property/KeyPrefix change and the regenerated JSON together." diff --git a/tika-metadata-schema/src/main/java/org/apache/tika/metadata/schema/SchemaGenerator.java b/tika-metadata-schema/src/main/java/org/apache/tika/metadata/schema/SchemaGenerator.java index 8a552319cc..2be82a94b4 100644 --- a/tika-metadata-schema/src/main/java/org/apache/tika/metadata/schema/SchemaGenerator.java +++ b/tika-metadata-schema/src/main/java/org/apache/tika/metadata/schema/SchemaGenerator.java @@ -32,7 +32,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.tika.digest.DigestDef; -import org.apache.tika.metadata.PassthroughPrefix; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Property; /** @@ -54,8 +54,8 @@ public final class SchemaGenerator { // Field/parameter descriptors in a .class constant pool: a class referencing one is force-loaded. private static final byte[] PROP_DESC = "Lorg/apache/tika/metadata/Property;".getBytes(StandardCharsets.ISO_8859_1); - private static final byte[] PASSTHROUGH_DESC = - "Lorg/apache/tika/metadata/PassthroughPrefix;".getBytes(StandardCharsets.ISO_8859_1); + private static final byte[] KEY_PREFIX_DESC = + "Lorg/apache/tika/metadata/KeyPrefix;".getBytes(StandardCharsets.ISO_8859_1); private SchemaGenerator() { } @@ -118,7 +118,7 @@ public final class SchemaGenerator { return fieldTableJson(rows); } - /** Scans the classpath, force-loads every Property/PassthroughPrefix-bearing class (static init + /** Scans the classpath, force-loads every Property/KeyPrefix-bearing class (static init * registers the constants), and returns the loaded class names. */ private static List<String> scanClasspath(ClassLoader cl) throws IOException { List<String> loaded = new ArrayList<>(); @@ -160,7 +160,7 @@ public final class SchemaGenerator { private static void maybeLoad(String classPath, byte[] bytes, ClassLoader cl, List<String> loaded) { if (!classPath.startsWith("org/apache/tika/") - || (!contains(bytes, PROP_DESC) && !contains(bytes, PASSTHROUGH_DESC))) { + || (!contains(bytes, PROP_DESC) && !contains(bytes, KEY_PREFIX_DESC))) { return; } String cn = classPath.substring(0, classPath.length() - 6).replace('/', '.'); @@ -222,7 +222,7 @@ public final class SchemaGenerator { /** Declared passthrough prefixes as stable JSON. Call after {@link #generate()} has loaded classes. */ public static String passthroughJson() { TreeMap<String, String[]> m = new TreeMap<>(); - for (PassthroughPrefix p : PassthroughPrefix.registered()) { + for (KeyPrefix p : KeyPrefix.registered()) { m.put(p.prefix(), new String[]{p.provenance().name(), p.description()}); } StringBuilder sb = new StringBuilder("[\n"); diff --git a/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataCoverageTest.java b/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataCoverageTest.java index 4980d770d1..eedd98975b 100644 --- a/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataCoverageTest.java +++ b/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataCoverageTest.java @@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test; * Completeness backstop for the standard-scoped registry. {@link MetadataSchemaTest} proves the * registry matches the declarations it <em>scans</em>; this proves nothing <em>escapes</em> the * scan. It greps the source tree for every module declaring a {@code Property} or - * {@code PassthroughPrefix} and fails if one is neither on the registry classpath nor an explicit + * {@code KeyPrefix} and fails if one is neither on the registry classpath nor an explicit * {@link #OUT_OF_SCOPE} family — so a new key-bearing parser cannot slip in silently. * * <p>Reads source (always present) for the declaring set and the runtime classpath for the scanned @@ -53,7 +53,7 @@ public class MetadataCoverageTest { // Source markers for an actual key declaration (a factory call), not a mere type reference. private static final String[] DECL_MARKERS = { "Property.internal", "Property.external", "Property.composite", - "PassthroughPrefix.file(", "PassthroughPrefix.tool("}; + "KeyPrefix.file(", "KeyPrefix.tool("}; private static final String SRC_MAIN = sep("src", "main") + File.separator + "java"; private static final String SRC_TEST = sep("src", "test"); diff --git a/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataSchemaTest.java b/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataSchemaTest.java index 5530b82b10..25cf6d8aef 100644 --- a/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataSchemaTest.java +++ b/tika-metadata-schema/src/test/java/org/apache/tika/metadata/schema/MetadataSchemaTest.java @@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test; /** * The CI gate: regenerate both registries from the live {@link org.apache.tika.metadata.Property} - * and {@link org.apache.tika.metadata.PassthroughPrefix} declarations and assert each matches its + * and {@link org.apache.tika.metadata.KeyPrefix} declarations and assert each matches its * committed file. If a declaration is added/changed/renamed without regenerating, this fails — the * registries cannot silently drift. */ @@ -44,7 +44,7 @@ public class MetadataSchemaTest { @Test public void committedOpenNamespacesMatchDeclarations() throws Exception { - // generate() first, so the classpath scan force-loads the PassthroughPrefix declarations. + // generate() first, so the classpath scan force-loads the KeyPrefix declarations. SchemaGenerator.generate(); assertEquals(committed(OPEN), SchemaGenerator.passthroughJson(), "metadata-open-namespaces.json is stale. Run tika-metadata-schema/regen.sh and " diff --git a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java index a4d902c882..19ef1f1cc4 100644 --- a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java +++ b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java @@ -33,8 +33,8 @@ import org.apache.tika.detect.AutoDetectReader; import org.apache.tika.detect.EncodingDetector; import org.apache.tika.exception.TikaException; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.AbstractEncodingDetectorParser; import org.apache.tika.parser.ParseContext; @@ -44,8 +44,8 @@ import org.apache.tika.sax.XHTMLContentHandler; public class EnviHeaderParser extends AbstractEncodingDetectorParser { public static final String ENVI_MIME_TYPE = "application/envi.hdr"; - public static final PassthroughPrefix ENVI = - PassthroughPrefix.file("envi.", "ENVI header field names"); + public static final KeyPrefix ENVI = + KeyPrefix.file("envi.", "ENVI header field names"); private static final long serialVersionUID = -1479368523072408091L; private static final Logger LOG = LoggerFactory.getLogger(EnviHeaderParser.class); private static final Set<MediaType> SUPPORTED_TYPES = diff --git a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java index 073eb7bf25..94f819f9f2 100644 --- a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java +++ b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/grib/GribParser.java @@ -36,8 +36,8 @@ import org.apache.tika.annotation.TikaComponent; import org.apache.tika.exception.TikaException; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.ClimateForcast; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.ParseContext; @@ -48,8 +48,8 @@ import org.apache.tika.sax.XHTMLContentHandler; public class GribParser implements Parser { public static final String GRIB_MIME_TYPE = "application/x-grib2"; - public static final PassthroughPrefix GRIB = - PassthroughPrefix.file("grib:", "GRIB global attribute names"); + public static final KeyPrefix GRIB = + KeyPrefix.file("grib:", "GRIB global attribute names"); private static final long serialVersionUID = 7855458954474247655L; private final Set<MediaType> SUPPORTED_TYPES = Collections.singleton(MediaType.application("x-grib2")); diff --git a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java index fe2300a976..1cc2cef3e2 100644 --- a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java +++ b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/netcdf/NetCDFParser.java @@ -34,8 +34,8 @@ import org.apache.tika.annotation.TikaComponent; import org.apache.tika.exception.TikaException; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.ClimateForcast; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.ParseContext; @@ -57,8 +57,8 @@ public class NetCDFParser implements Parser { */ private static final long serialVersionUID = -5940938274907708665L; - public static final PassthroughPrefix NETCDF = - PassthroughPrefix.file("netcdf:", "NetCDF global attribute names"); + public static final KeyPrefix NETCDF = + KeyPrefix.file("netcdf:", "NetCDF global attribute names"); private final Set<MediaType> SUPPORTED_TYPES = Collections.singleton(MediaType.application("x-netcdf")); diff --git a/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ctakes/CTAKESContentHandler.java b/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ctakes/CTAKESContentHandler.java index bb6ae8cdcf..9decddcad4 100644 --- a/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ctakes/CTAKESContentHandler.java +++ b/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ctakes/CTAKESContentHandler.java @@ -26,8 +26,8 @@ import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.sax.ContentHandlerDecorator; /** @@ -42,8 +42,8 @@ import org.apache.tika.sax.ContentHandlerDecorator; public class CTAKESContentHandler extends ContentHandlerDecorator { // Prefix used for metadata including cTAKES annotations public static String CTAKES_META_PREFIX = "ctakes:"; - public static final PassthroughPrefix CTAKES = - PassthroughPrefix.tool(CTAKES_META_PREFIX, "cTAKES annotation type names"); + public static final KeyPrefix CTAKES = + KeyPrefix.tool(CTAKES_META_PREFIX, "cTAKES annotation type names"); // Configuration object for CTAKESContentHandler private CTAKESConfig config = null; diff --git a/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/journal/GrobidRESTParser.java b/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/journal/GrobidRESTParser.java index 3eab5ee4de..1ad472cf1c 100644 --- a/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/journal/GrobidRESTParser.java +++ b/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/journal/GrobidRESTParser.java @@ -34,8 +34,8 @@ import org.xml.sax.ContentHandler; import org.apache.tika.annotation.TikaComponent; import org.apache.tika.exception.TikaException; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.parser.ParseContext; /** @@ -47,8 +47,8 @@ public class GrobidRESTParser { private static final Logger LOG = LoggerFactory.getLogger(GrobidRESTParser.class); - public static final PassthroughPrefix GROBID_HEADER = - PassthroughPrefix.tool("grobid:header_", "GROBID-inferred header fields"); + public static final KeyPrefix GROBID_HEADER = + KeyPrefix.tool("grobid:header_", "GROBID-inferred header fields"); private static final String GROBID_REST_HOST = "http://localhost:8070"; private static final String GROBID_ISALIVE_PATH = "/api/isalive"; diff --git a/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ner/NamedEntityParser.java b/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ner/NamedEntityParser.java index 52df871ded..9cd2f8a0d5 100644 --- a/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ner/NamedEntityParser.java +++ b/tika-parsers/tika-parsers-ml/tika-parser-nlp-module/src/main/java/org/apache/tika/parser/ner/NamedEntityParser.java @@ -37,8 +37,8 @@ import org.apache.tika.annotation.TikaComponent; import org.apache.tika.config.loader.TikaLoader; import org.apache.tika.exception.TikaException; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; @@ -62,8 +62,8 @@ public class NamedEntityParser implements Parser { public static final Logger LOG = LoggerFactory.getLogger(NamedEntityParser.class); public static final Set<MediaType> MEDIA_TYPES = new HashSet<>(); public static final String MD_KEY_PREFIX = "NER_"; - public static final PassthroughPrefix NER = - PassthroughPrefix.tool(MD_KEY_PREFIX, "named-entity types"); + public static final KeyPrefix NER = + KeyPrefix.tool(MD_KEY_PREFIX, "named-entity types"); public static final String DEFAULT_NER_IMPL = OpenNLPNERecogniser.class.getName() + "," + RegexNERecogniser.class.getName(); public static final String SYS_PROP_NER_IMPL = "ner.impl.class"; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/NumbersContentHandler.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/NumbersContentHandler.java index 87237ffca9..cb292057f1 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/NumbersContentHandler.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/NumbersContentHandler.java @@ -23,16 +23,16 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.Office; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.sax.XHTMLContentHandler; class NumbersContentHandler extends DefaultHandler { - private static final PassthroughPrefix NUMBERS_METADATA = - PassthroughPrefix.file("numbers:", "iWork Numbers document metadata element names"); + private static final KeyPrefix NUMBERS_METADATA = + KeyPrefix.file("numbers:", "iWork Numbers document metadata element names"); private final XHTMLContentHandler xhtml; private final Metadata metadata; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/iwana/IWork13PackageParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/iwana/IWork13PackageParser.java index 1ffb5fa5ec..797157e49f 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/iwana/IWork13PackageParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-apple-module/src/main/java/org/apache/tika/parser/iwork/iwana/IWork13PackageParser.java @@ -44,8 +44,8 @@ import org.apache.tika.extractor.EmbeddedDocumentExtractor; import org.apache.tika.extractor.EmbeddedDocumentUtil; import org.apache.tika.io.TemporaryResources; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; @@ -67,8 +67,8 @@ public class IWork13PackageParser implements Parser { Property.externalText(IWORKS_PREFIX + "document-id"); public static final Property IWORKS_BUILD_VERSION_HISTORY = Property.externalTextBag(IWORKS_PREFIX + "build-version-history"); - public static final PassthroughPrefix IWORKS_PROPERTIES = - PassthroughPrefix.file(IWORKS_PREFIX, "iWork '13 plist document properties"); + public static final KeyPrefix IWORKS_PROPERTIES = + KeyPrefix.file(IWORKS_PREFIX, "iWork '13 plist document properties"); private final static Set<MediaType> supportedTypes = Collections.unmodifiableSet( diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java index 7d0b043889..f583c4fb56 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java @@ -41,8 +41,8 @@ import org.apache.tika.extractor.EmbeddedDocumentExtractor; import org.apache.tika.extractor.EmbeddedDocumentUtil; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Audio; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.metadata.XMP; import org.apache.tika.metadata.XMPDM; @@ -59,8 +59,8 @@ import org.apache.tika.sax.XHTMLContentHandler; public abstract class OggAudioParser extends AbstractParser { private static final long serialVersionUID = 5168743829615945633L; - private static final PassthroughPrefix VORBIS = - PassthroughPrefix.file("vorbis:", "Vorbis comment field names"); + private static final KeyPrefix VORBIS = + KeyPrefix.file("vorbis:", "Vorbis comment field names"); /** * Comment holding an embedded picture (e.g. cover art) as a base64 diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/video/FLVParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/video/FLVParser.java index 32900f319e..036362338d 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/video/FLVParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/video/FLVParser.java @@ -35,8 +35,8 @@ import org.xml.sax.SAXException; import org.apache.tika.annotation.TikaComponent; import org.apache.tika.exception.TikaException; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; @@ -77,8 +77,8 @@ public class FLVParser implements Parser { private static int TYPE_METADATA = 0x12; private static byte MASK_AUDIO = 1; private static byte MASK_VIDEO = 4; - private static final PassthroughPrefix FLV = - PassthroughPrefix.file("flv:", "FLV onMetaData tag keys"); + private static final KeyPrefix FLV = + KeyPrefix.file("flv:", "FLV onMetaData tag keys"); public Set<MediaType> getSupportedTypes(ParseContext context) { return SUPPORTED_TYPES; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/src/main/java/org/apache/tika/parser/dwg/DWGParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/src/main/java/org/apache/tika/parser/dwg/DWGParser.java index a03578d0eb..4c7eafcd03 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/src/main/java/org/apache/tika/parser/dwg/DWGParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/src/main/java/org/apache/tika/parser/dwg/DWGParser.java @@ -31,8 +31,8 @@ import org.apache.tika.config.JsonConfig; import org.apache.tika.exception.TikaException; import org.apache.tika.io.EndianUtils; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; @@ -61,8 +61,8 @@ public class DWGParser extends AbstractDWGParser { } public static String DWG_CUSTOM_META_PREFIX = "dwg-custom:"; - public static final PassthroughPrefix DWG_CUSTOM = - PassthroughPrefix.file(DWG_CUSTOM_META_PREFIX, "DWG custom document properties"); + public static final KeyPrefix DWG_CUSTOM = + KeyPrefix.file(DWG_CUSTOM_META_PREFIX, "DWG custom document properties"); /** * Serial version UID */ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java index 4008c39910..872bda41eb 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java @@ -72,8 +72,8 @@ import org.xml.sax.SAXException; import org.apache.tika.exception.TikaException; import org.apache.tika.metadata.Geographic; import org.apache.tika.metadata.IPTC; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TIFF; import org.apache.tika.metadata.TikaCoreProperties; @@ -93,10 +93,10 @@ public class ImageMetadataExtractor { public static final String UNKNOWN_IMG_NS = "img" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; public static final String ICC_NS = "ICC" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - public static final PassthroughPrefix UNKNOWN_IMG = - PassthroughPrefix.file(UNKNOWN_IMG_NS, "unrecognized image tag names"); - public static final PassthroughPrefix ICC = - PassthroughPrefix.file(ICC_NS, "unrecognized ICC profile tag names"); + public static final KeyPrefix UNKNOWN_IMG = + KeyPrefix.file(UNKNOWN_IMG_NS, "unrecognized image tag names"); + public static final KeyPrefix ICC = + KeyPrefix.file(ICC_NS, "unrecognized ICC profile tag names"); private final Metadata metadata; private DirectoryHandler[] handlers; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-mail-module/src/main/java/org/apache/tika/parser/mbox/MboxParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-mail-module/src/main/java/org/apache/tika/parser/mbox/MboxParser.java index 16622cbc2b..4ce712b57a 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-mail-module/src/main/java/org/apache/tika/parser/mbox/MboxParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-mail-module/src/main/java/org/apache/tika/parser/mbox/MboxParser.java @@ -41,9 +41,9 @@ import org.apache.tika.exception.TikaException; import org.apache.tika.extractor.EmbeddedDocumentExtractor; import org.apache.tika.extractor.EmbeddedDocumentUtil; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Message; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; @@ -73,8 +73,8 @@ public class MboxParser implements Parser { private static final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile("<(.*@.*)>"); private static final String EMAIL_HEADER_METADATA_PREFIX = "MboxParser-"; - private static final PassthroughPrefix EMAIL_HEADER = - PassthroughPrefix.file(EMAIL_HEADER_METADATA_PREFIX, "mbox email header names"); + private static final KeyPrefix EMAIL_HEADER = + KeyPrefix.file(EMAIL_HEADER_METADATA_PREFIX, "mbox email header names"); private static final String EMAIL_FROMLINE_METADATA = EMAIL_HEADER_METADATA_PREFIX + "from"; private final Map<Integer, Metadata> trackingMetadata = new HashMap<>(); private boolean tracking = false; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/JackcessParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/JackcessParser.java index 1d86b6fd98..71f60ef733 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/JackcessParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/JackcessParser.java @@ -34,8 +34,8 @@ import org.apache.tika.exception.EncryptedDocumentException; import org.apache.tika.exception.TikaException; import org.apache.tika.exception.UnsupportedFormatException; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; @@ -56,8 +56,8 @@ public class JackcessParser implements Parser { public static final String SUMMARY_PROPERTY_PREFIX = "mdb-summary-prop" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - public static final PassthroughPrefix MDB_SUMMARY_PROPERTY = - PassthroughPrefix.file(SUMMARY_PROPERTY_PREFIX, "MS Access summary properties"); + public static final KeyPrefix MDB_SUMMARY_PROPERTY = + KeyPrefix.file(SUMMARY_PROPERTY_PREFIX, "MS Access summary properties"); private final static LinkResolver IGNORE_LINK_RESOLVER = new IgnoreLinkResolver(); private static final long serialVersionUID = -752276948656079347L; private static final MediaType MEDIA_TYPE = MediaType.application("x-msaccess"); @@ -67,12 +67,12 @@ public class JackcessParser implements Parser { // public static Property LINKED_DATABASES = Property.externalTextBag("LinkedDatabases"); public static String MDB_PROPERTY_PREFIX = "mdb-prop" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - public static final PassthroughPrefix MDB_PROPERTY = - PassthroughPrefix.file(MDB_PROPERTY_PREFIX, "MS Access database properties"); + public static final KeyPrefix MDB_PROPERTY = + KeyPrefix.file(MDB_PROPERTY_PREFIX, "MS Access database properties"); public static String USER_DEFINED_PROPERTY_PREFIX = "mdb-user-prop" + TikaCoreProperties.NAMESPACE_PREFIX_DELIMITER; - public static final PassthroughPrefix MDB_USER_PROPERTY = - PassthroughPrefix.file(USER_DEFINED_PROPERTY_PREFIX, "MS Access user-defined properties"); + public static final KeyPrefix MDB_USER_PROPERTY = + KeyPrefix.file(USER_DEFINED_PROPERTY_PREFIX, "MS Access user-defined properties"); public static Property MDB_PW = Property.externalText("mdb:password"); private Locale locale = Locale.ROOT; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-webarchive-module/src/main/java/org/apache/tika/parser/warc/WARCParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-webarchive-module/src/main/java/org/apache/tika/parser/warc/WARCParser.java index 7206d6c7ca..9e5198d91d 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-webarchive-module/src/main/java/org/apache/tika/parser/warc/WARCParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-webarchive-module/src/main/java/org/apache/tika/parser/warc/WARCParser.java @@ -39,8 +39,8 @@ import org.apache.tika.exception.WriteLimitReachedException; import org.apache.tika.extractor.EmbeddedDocumentExtractor; import org.apache.tika.extractor.EmbeddedDocumentUtil; import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.metadata.WARC; @@ -65,10 +65,10 @@ public class WARCParser implements Parser { public static String WARC_PREFIX = "warc:"; public static String WARC_HTTP_PREFIX = WARC_PREFIX + "http:"; - public static final PassthroughPrefix WARC_HEADER = - PassthroughPrefix.file(WARC_PREFIX, "WARC record header names"); - public static final PassthroughPrefix WARC_HTTP_HEADER = - PassthroughPrefix.file(WARC_HTTP_PREFIX, "WARC HTTP response header names"); + public static final KeyPrefix WARC_HEADER = + KeyPrefix.file(WARC_PREFIX, "WARC record header names"); + public static final KeyPrefix WARC_HTTP_HEADER = + KeyPrefix.file(WARC_HTTP_PREFIX, "WARC HTTP response header names"); public static String WARC_HTTP_STATUS = WARC_HTTP_PREFIX + "status"; diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-xmp-commons/src/main/java/org/apache/tika/parser/xmp/XmpExtractor.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-xmp-commons/src/main/java/org/apache/tika/parser/xmp/XmpExtractor.java index 3b96b3af0b..468f5c47cc 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-xmp-commons/src/main/java/org/apache/tika/parser/xmp/XmpExtractor.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-xmp-commons/src/main/java/org/apache/tika/parser/xmp/XmpExtractor.java @@ -35,11 +35,11 @@ import org.xml.sax.SAXException; import org.apache.tika.exception.TikaException; import org.apache.tika.metadata.DublinCore; import org.apache.tika.metadata.Google; +import org.apache.tika.metadata.KeyPrefix; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.Office; import org.apache.tika.metadata.PDF; import org.apache.tika.metadata.PagedText; -import org.apache.tika.metadata.PassthroughPrefix; import org.apache.tika.metadata.Photoshop; import org.apache.tika.metadata.Property; import org.apache.tika.metadata.TIFF; @@ -77,7 +77,7 @@ public class XmpExtractor { // tk: field. Best-effort discovery surface: keys use the document's prefix (not the URI) // and are non-contractual -- promote a field into TABLE when it needs a stable key. static final String RAW_PREFIX = "xmp-raw:"; - static final PassthroughPrefix RAW = PassthroughPrefix.file(RAW_PREFIX, "unmapped XMP keys"); + static final KeyPrefix RAW = KeyPrefix.file(RAW_PREFIX, "unmapped XMP keys"); // strip a trailing array index so a raw bag/seq is one multi-valued key, not foo:Bag[1], foo:Bag[2] private static final Pattern TRAILING_INDEX = Pattern.compile("\\[\\d+\\]$");
