2525import java .lang .reflect .Constructor ;
2626import java .lang .reflect .Field ;
2727import java .lang .reflect .InvocationTargetException ;
28+ import java .util .ArrayList ;
2829import java .util .Calendar ;
2930import java .util .EnumMap ;
3031import java .util .HashMap ;
32+ import java .util .List ;
3133import java .util .Map ;
3234
3335import javax .xml .namespace .QName ;
4345import org .apache .xmpbox .schema .XMPBasicJobTicketSchema ;
4446import org .apache .xmpbox .schema .XMPBasicSchema ;
4547import org .apache .xmpbox .schema .XMPMediaManagementSchema ;
48+ import org .apache .xmpbox .schema .XMPPageTextSchema ;
4649import org .apache .xmpbox .schema .XMPRightsManagementSchema ;
4750import org .apache .xmpbox .schema .XMPSchema ;
4851import org .apache .xmpbox .schema .XMPSchemaFactory ;
49- import org .apache .xmpbox .schema .XMPPageTextSchema ;
52+ import org .apache .xmpbox .schema .XmpSchemaException ;
5053
5154public 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
0 commit comments