View Javadoc
1   /*
2    * Copyright 2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.openehealth.ipf.commons.ihe.xds.core;
17  
18  import org.apache.cxf.jaxb.JAXBDataBinding;
19  import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.lcm.SubmitObjectsRequest;
20  import org.openehealth.ipf.commons.ihe.xds.core.stub.ebrs30.rim.*;
21  
22  import javax.xml.bind.Marshaller;
23  import javax.xml.bind.Unmarshaller;
24  import java.util.*;
25  
26  /**
27   * Data binding specific for the XDS data model --- gathers some additional
28   * information pieces for elements of request messages while they are being
29   * unmarshalled from XML to ebXML POJOs.  These information pieces are
30   * intended to be propagated into Camel route as message headers.
31   *
32   * @author Dmytro Rud
33   */
34  public class XdsJaxbDataBinding extends JAXBDataBinding {
35  
36      public static final String SUBMISSION_SET_HAS_EXTRA_METADATA =
37              XdsJaxbDataBinding.class.getName() + ".submission.set.has.extra.metadata";
38  
39      private static final Map<Object, Map<String, Object>> DATA =
40              Collections.synchronizedMap(new WeakHashMap<Object, Map<String, Object>>());
41  
42  
43      /**
44       * Returns a map of additional Camel headers for the given ebXML object.
45       * <p>
46       * NB: not declared <tt>synchronized</tt>, because no ebXML object
47       * is supposed to be marshaled/unmarshaled from multiple threads.
48       *
49       * @param ebXml key object.
50       * @return additional Camel headers as a map.
51       */
52      public static Map<String, Object> getCamelHeaders(Object ebXml) {
53          return DATA.computeIfAbsent(ebXml, k -> new HashMap<>());
54      }
55  
56  
57      public XdsJaxbDataBinding() {
58          super();
59          setUnmarshallerListener(new UnmarshallerListener());
60          setMarshallerListener(new MarshallerListener());
61      }
62  
63  
64      public static boolean isExtraMetadataSlotName(String name) {
65          return ((name != null) && name.startsWith("urn:") && (!name.startsWith("urn:ihe:")));
66      }
67  
68  
69      private static class UnmarshallerListener extends Unmarshaller.Listener {
70          static final ThreadLocal<Boolean> RESULTS = new ThreadLocal<>();
71  
72          @Override
73          public void afterUnmarshal(Object target, Object parent) {
74              if (target instanceof ExtrinsicObjectType) {
75                  ExtrinsicObjectType ebXml = (ExtrinsicObjectType) target;
76                  findExtraMetadata(ebXml.getSlot(), ebXml);
77              } else if (target instanceof RegistryPackageType) {
78                  RegistryPackageType ebXml = (RegistryPackageType) target;
79                  findExtraMetadata(ebXml.getSlot(), ebXml);
80              } else if (target instanceof AssociationType1) {
81                  AssociationType1 ebXml = (AssociationType1) target;
82                  findExtraMetadata(ebXml.getSlot(), ebXml);
83              } else if ((target instanceof SubmitObjectsRequest) && Boolean.TRUE.equals(RESULTS.get())) {
84                  getCamelHeaders(target).put(SUBMISSION_SET_HAS_EXTRA_METADATA, Boolean.TRUE);
85                  RESULTS.remove();
86              }
87          }
88  
89          private static void findExtraMetadata(List<SlotType1> slots, ExtraMetadataHolder holder) {
90              if (slots != null) {
91                  for (SlotType1 slot : slots) {
92                      String name = slot.getName();
93                      if (isExtraMetadataSlotName(name)) {
94                          Map<String, List<String>> extraMetadata = holder.getExtraMetadata();
95                          if (extraMetadata == null) {
96                              extraMetadata = new HashMap<>();
97                              holder.setExtraMetadata(extraMetadata);
98                          }
99                          extraMetadata.put(name, new ArrayList<>(slot.getValueList().getValue()));
100                         RESULTS.set(Boolean.TRUE);
101                     }
102                 }
103             }
104         }
105     }
106 
107 
108     private static class MarshallerListener extends Marshaller.Listener {
109         @Override
110         public void beforeMarshal(Object source) {
111             if (source instanceof ExtrinsicObjectType) {
112                 ExtrinsicObjectType ebXml = (ExtrinsicObjectType) source;
113                 injectExtraMetadata(ebXml.getSlot(), ebXml);
114             } else if (source instanceof RegistryPackageType) {
115                 RegistryPackageType ebXml = (RegistryPackageType) source;
116                 injectExtraMetadata(ebXml.getSlot(), ebXml);
117             } else if (source instanceof AssociationType1) {
118                 AssociationType1 ebXml = (AssociationType1) source;
119                 injectExtraMetadata(ebXml.getSlot(), ebXml);
120             }
121         }
122 
123         private static void injectExtraMetadata(List<SlotType1> slots, ExtraMetadataHolder holder) {
124             if (holder.getExtraMetadata() != null) {
125                 holder.getExtraMetadata().entrySet().stream()
126                         .filter(entry -> isExtraMetadataSlotName(entry.getKey()))
127                         .forEach(entry -> {
128                             SlotType1 slot = new SlotType1();
129                             slot.setName(entry.getKey());
130                             ValueListType valueList = new ValueListType();
131                             valueList.getValue().addAll(entry.getValue());
132                             slot.setValueList(valueList);
133                             slots.add(slot);
134                         });
135             }
136         }
137     }
138 
139 }