Skip to content

Commit 6767f77

Browse files
committed
PDFBOX-6133: try type namespace after failing schema namespace, while making sure to keep old behavior when failing; pass local name because there can be several types for the same namespace; add tests
git-svn-id: https://svn.apache.org/repos/asf/pdfbox/trunk@1930916 13f79535-47bb-0310-9956-ffa450edef68
1 parent 4ab6f90 commit 6767f77

File tree

3 files changed

+217
-28
lines changed

3 files changed

+217
-28
lines changed

xmpbox/src/main/java/org/apache/xmpbox/type/TypeMapping.java

Lines changed: 157 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
import java.lang.reflect.Constructor;
2626
import java.lang.reflect.Field;
2727
import java.lang.reflect.InvocationTargetException;
28+
import java.util.ArrayList;
2829
import java.util.Calendar;
2930
import java.util.EnumMap;
3031
import java.util.HashMap;
32+
import java.util.List;
3133
import java.util.Map;
3234

3335
import javax.xml.namespace.QName;
@@ -43,24 +45,37 @@
4345
import org.apache.xmpbox.schema.XMPBasicJobTicketSchema;
4446
import org.apache.xmpbox.schema.XMPBasicSchema;
4547
import org.apache.xmpbox.schema.XMPMediaManagementSchema;
48+
import org.apache.xmpbox.schema.XMPPageTextSchema;
4649
import org.apache.xmpbox.schema.XMPRightsManagementSchema;
4750
import org.apache.xmpbox.schema.XMPSchema;
4851
import org.apache.xmpbox.schema.XMPSchemaFactory;
49-
import org.apache.xmpbox.schema.XMPPageTextSchema;
52+
import org.apache.xmpbox.schema.XmpSchemaException;
5053

5154
public final class TypeMapping
5255
{
5356

57+
// type -> property
5458
private Map<Types, PropertiesDescription> structuredMappings;
5559

5660
// ns -> type
61+
// filled during init
62+
@Deprecated
5763
private Map<String, Types> structuredNamespaces;
5864

59-
// ns -> type
65+
// ns -> typeName
66+
@Deprecated
6067
private Map<String, String> definedStructuredNamespaces;
6168

69+
// ns -> list of property descriptions
70+
private Map<String, List<PropertiesDescription>> definedStructuredNamespaces2;
71+
72+
// typeName -> property
6273
private Map<String, PropertiesDescription> definedStructuredMappings;
6374

75+
// ns -> type
76+
// filled during init
77+
private Map<String, List<Types>> structuredNamespaces2;
78+
6479
private final XMPMetadata metadata;
6580

6681
private Map<String, XMPSchemaFactory> schemaMap;
@@ -79,6 +94,7 @@ private void initialize()
7994
// structured types
8095
structuredMappings = new EnumMap<>(Types.class);
8196
structuredNamespaces = new HashMap<>();
97+
structuredNamespaces2 = new HashMap<>();
8298
for (Types type : Types.values())
8399
{
84100
if (type.isStructured())
@@ -89,13 +105,25 @@ private void initialize()
89105
String ns = st.namespace();
90106
PropertiesDescription pm = initializePropMapping(clz);
91107
structuredNamespaces.put(ns, type);
108+
List<Types> list = structuredNamespaces2.get(ns);
109+
if (list != null)
110+
{
111+
list.add(type);
112+
}
113+
else
114+
{
115+
list = new ArrayList<>();
116+
list.add(type);
117+
structuredNamespaces2.put(ns, list);
118+
}
92119
structuredMappings.put(type, pm);
93120
}
94121
}
95122

96123
// define structured types
97124
definedStructuredNamespaces = new HashMap<>();
98125
definedStructuredMappings = new HashMap<>();
126+
definedStructuredNamespaces2 = new HashMap<>();
99127

100128
// schema
101129
schemaMap = new HashMap<>();
@@ -115,14 +143,49 @@ private void initialize()
115143

116144
public void addToDefinedStructuredTypes(String typeName, String ns, PropertiesDescription pm)
117145
{
146+
List<PropertiesDescription> list = definedStructuredNamespaces2.get(ns);
147+
if (list != null)
148+
{
149+
list.add(pm);
150+
}
151+
else
152+
{
153+
list = new ArrayList<>();
154+
list.add(pm);
155+
definedStructuredNamespaces2.put(ns, list);
156+
}
118157
definedStructuredNamespaces.put(ns, typeName);
119158
definedStructuredMappings.put(typeName, pm);
120159
}
121160

161+
@Deprecated
122162
public PropertiesDescription getDefinedDescriptionByNamespace(String namespace)
123163
{
124164
String dt = definedStructuredNamespaces.get(namespace);
125-
return this.definedStructuredMappings.get(dt);
165+
return definedStructuredMappings.get(dt);
166+
}
167+
168+
/**
169+
* Get a property description based on namespace and field name. Both are needed because there
170+
* can be several property descriptions for one namespace.
171+
*
172+
* @param namespace
173+
* @param pdfaFieldName
174+
* @return
175+
*/
176+
public PropertiesDescription getDefinedDescriptionByNamespace(String namespace, String pdfaFieldName)
177+
{
178+
List<PropertiesDescription> propDescList = definedStructuredNamespaces2.get(namespace);
179+
// gets list of type names (not to be confused with field names / property names)
180+
for (PropertiesDescription propDesc : propDescList)
181+
{
182+
// check whether one of these field names matches
183+
if (propDesc.getPropertiesNames().contains(pdfaFieldName))
184+
{
185+
return propDesc;
186+
}
187+
}
188+
return null;
126189
}
127190

128191
public AbstractStructuredType instanciateStructuredType(Types type, String propertyName)
@@ -189,17 +252,17 @@ public AbstractSimpleProperty instanciateSimpleField(Class<?> clz, String nsuri,
189252
*/
190253
public boolean isStructuredTypeNamespace(String namespace)
191254
{
192-
return structuredNamespaces.containsKey(namespace);
255+
return structuredNamespaces2.containsKey(namespace);
193256
}
194257

195258
public boolean isDefinedTypeNamespace(String namespace)
196259
{
197-
return definedStructuredNamespaces.containsKey(namespace);
260+
return definedStructuredNamespaces2.containsKey(namespace);
198261
}
199262

200263
public boolean isDefinedType(String name)
201264
{
202-
return this.definedStructuredMappings.containsKey(name);
265+
return definedStructuredMappings.containsKey(name);
203266
}
204267

205268
private void addNameSpace(Class<? extends XMPSchema> classSchem)
@@ -220,6 +283,37 @@ public PropertiesDescription getStructuredPropMapping(Types type)
220283
return structuredMappings.get(type);
221284
}
222285

286+
/**
287+
* Return the specialized schema class representation if it's known (create and add it to metadata). In other cases,
288+
* return null
289+
*
290+
* @param metadata
291+
* Metadata to link the new schema
292+
* @param namespace
293+
* The namespace URI
294+
* @param prefix The namespace prefix
295+
* @return Schema representation
296+
* @throws XmpSchemaException
297+
* When Instancing specified Object Schema failed
298+
*
299+
* @deprecated This method will be removed in 4.0. If you need it, let us know.
300+
*/
301+
@Deprecated
302+
public XMPSchema getAssociatedSchemaObject(XMPMetadata metadata, String namespace, String prefix)
303+
throws XmpSchemaException
304+
{
305+
if (schemaMap.containsKey(namespace))
306+
{
307+
XMPSchemaFactory factory = schemaMap.get(namespace);
308+
return factory.createXMPSchema(metadata, prefix);
309+
}
310+
else
311+
{
312+
XMPSchemaFactory factory = getSchemaFactory(namespace);
313+
return factory != null ? factory.createXMPSchema(metadata, prefix) : null;
314+
}
315+
}
316+
223317
public XMPSchemaFactory getSchemaFactory(String namespace)
224318
{
225319
return schemaMap.get(namespace);
@@ -257,30 +351,73 @@ public PropertyType getSpecifiedPropertyType(QName qName, String parentTypeName)
257351
if (factory != null)
258352
{
259353
// found in schema
260-
return factory.getPropertyType(qName.getLocalPart());
354+
PropertyType propertyType = factory.getPropertyType(qName.getLocalPart());
355+
if (propertyType != null)
356+
{
357+
return propertyType;
358+
}
261359
}
262-
else
360+
// try in structured
361+
List<Types> list = structuredNamespaces2.get(qName.getNamespaceURI());
362+
Types st;
363+
if (list != null)
263364
{
264-
// try in structured
265-
Types st = structuredNamespaces.get(qName.getNamespaceURI());
266-
if (st != null)
365+
st = list.get(0);
366+
if (list.size() == 1)
267367
{
268-
return createPropertyType(st, Cardinality.Simple);
368+
PropertiesDescription propDesc = structuredMappings.get(st);
369+
if (factory == null || propDesc.getPropertiesNames().contains(qName.getLocalPart()))
370+
{
371+
return createPropertyType(st, Cardinality.Simple);
372+
}
373+
return null;
269374
}
270-
else
375+
if (list.size() > 1)
271376
{
272-
// try in defined
273-
String dt = definedStructuredNamespaces.get(qName.getNamespaceURI());
274-
if (dt == null)
377+
for (Types type : list)
275378
{
276-
// not found
277-
throw new BadFieldValueException("No descriptor found for " + qName);
379+
if (type.name().equals(parentTypeName))
380+
{
381+
return createPropertyType(type, Cardinality.Simple);
382+
}
278383
}
279-
else
384+
for (Types type : list)
280385
{
281-
return createPropertyType(Types.DefinedType, Cardinality.Simple);
386+
PropertiesDescription propDesc = structuredMappings.get(type);
387+
if (propDesc.getPropertiesNames().contains(qName.getLocalPart()))
388+
{
389+
st = type;
390+
break;
391+
}
282392
}
283393
}
394+
395+
PropertyType propertyType = createPropertyType(st, Cardinality.Simple);
396+
PropertiesDescription propertiesDescription = getStructuredPropMapping(propertyType.type());
397+
// PDFBOX-6133: do an additional check to make sure that the name exists.
398+
// This can happen with photoshop and exif because the namespace exists as a schema and as a type
399+
if (propertiesDescription.getPropertiesNames().contains(qName.getLocalPart()))
400+
{
401+
return propertyType;
402+
}
403+
return null;
404+
}
405+
else
406+
{
407+
// try in defined
408+
if (!definedStructuredNamespaces2.containsKey(qName.getNamespaceURI()))
409+
{
410+
// not found
411+
if (factory != null)
412+
{
413+
return null; // pre PDFBOX-6133 behavior
414+
}
415+
throw new BadFieldValueException("No descriptor found for " + qName);
416+
}
417+
else
418+
{
419+
return createPropertyType(Types.DefinedType, Cardinality.Simple);
420+
}
284421
}
285422
}
286423

xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ private AbstractField parseLiElement(XMPMetadata xmp, QName descriptor, Element
737737
}
738738
else
739739
{
740-
pm = tm.getDefinedDescriptionByNamespace(liElement.getNamespaceURI());
740+
pm = tm.getDefinedDescriptionByNamespace(liElement.getNamespaceURI(), liElement.getLocalName());
741741
}
742742
af = tryParseAttributesAsProperties(xmp, liElement, tm, (AbstractStructuredType) af, pm, null);
743743
}
@@ -815,7 +815,7 @@ private AbstractStructuredType parseLiDescription(XMPMetadata xmp, QName parentQ
815815
}
816816
else
817817
{
818-
pm = tm.getDefinedDescriptionByNamespace(firstLiDescriptionElementChild.getNamespaceURI());
818+
pm = tm.getDefinedDescriptionByNamespace(firstLiDescriptionElementChild.getNamespaceURI(), firstLiDescriptionElementChild.getLocalName());
819819
}
820820
for (Element liDescriptionElementChild : liDescriptionElementChildren)
821821
{
@@ -1126,7 +1126,7 @@ private PropertyType checkPropertyDefinition(XMPMetadata xmp, QName qName, Strin
11261126
}
11271127
try
11281128
{
1129-
return tm.getSpecifiedPropertyType(qName, null);
1129+
return tm.getSpecifiedPropertyType(qName, parentTypeName);
11301130
}
11311131
catch (BadFieldValueException e)
11321132
{
@@ -1200,7 +1200,7 @@ else if (XmpConstants.DEFAULT_RDF_PREFIX.equals(attr.getPrefix()))
12001200
}
12011201
else
12021202
{
1203-
pm = tm.getDefinedDescriptionByNamespace(attr.getNamespaceURI());
1203+
pm = tm.getDefinedDescriptionByNamespace(attr.getNamespaceURI(), attr.getLocalName());
12041204
}
12051205
}
12061206
if (ast != null && pm != null && attr.getNamespaceURI() != null)

0 commit comments

Comments
 (0)