1 | /*
|
---|
2 | * To change this template, choose Tools | Templates
|
---|
3 | * and open the template in the editor.
|
---|
4 | */
|
---|
5 | package gov.hhs.fha.nhinc.cpp;
|
---|
6 |
|
---|
7 | import com.sun.imageio.plugins.common.InputStreamAdapter;
|
---|
8 | import gov.hhs.fha.nhinc.mpilib.*;
|
---|
9 | import org.w3c.dom.*;
|
---|
10 | import javax.xml.parsers.DocumentBuilderFactory;
|
---|
11 | import javax.xml.parsers.*;
|
---|
12 | import javax.xml.transform.*;
|
---|
13 | import javax.xml.transform.dom.*;
|
---|
14 | import javax.xml.transform.stream.*;
|
---|
15 | import sun.util.logging.resources.logging;
|
---|
16 | import javax.xml.transform.*;
|
---|
17 | import javax.xml.transform.dom.*;
|
---|
18 | import javax.xml.transform.stream.*;
|
---|
19 | import java.io.StringWriter;
|
---|
20 | import gov.hhs.fha.nhinc.mpilib.PersonName;
|
---|
21 | import java.io.ByteArrayInputStream;
|
---|
22 | import java.io.InputStream;
|
---|
23 | import java.io.StringReader;
|
---|
24 | import org.xml.sax.InputSource;
|
---|
25 | import org.xml.sax.helpers.XMLReaderAdapter;
|
---|
26 | import gov.hhs.fha.nhinc.properties.PropertyAccessor;
|
---|
27 | import org.apache.commons.logging.Log;
|
---|
28 | import org.apache.commons.logging.LogFactory;
|
---|
29 |
|
---|
30 | /**
|
---|
31 | *
|
---|
32 | * @author dunnek
|
---|
33 | */
|
---|
34 | public class CPPUtils {
|
---|
35 |
|
---|
36 | private static Log log = LogFactory.getLog(CPPUtils.class);
|
---|
37 | static final String OPT_IN_RULE_ID = "126";
|
---|
38 | static final String OPT_OUT_RULE_ID = "125";
|
---|
39 | static final String DENY_DESCR = "deny all access to documents.";
|
---|
40 | static final String PERMIT_DESCR = "permit all access to documents.";
|
---|
41 | static final String OPT_IN_EFFECT = "Permit";
|
---|
42 | static final String OPT_OUT_EFFECT = "Deny";
|
---|
43 | private static final String RULE_TAG = "Rule";
|
---|
44 | private static final String RULE_ID_ATTR = "RuleId";
|
---|
45 | private static final String RULE_EFFECT_ATTR = "Effect";
|
---|
46 | private static final String ROOT_ATTR = "Root";
|
---|
47 | private static final String PATID_TAG = "PatientId";
|
---|
48 | private static final int SEND_SLEEP_COUNT = 15;
|
---|
49 | private static final long SEND_SLEEP_TIME_MS = 1000L;
|
---|
50 | private static final String basePolicy = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
---|
51 | "<Policy xmlns=\"urn:oasis:names:tc:xacml:2.0:policy:schema:os\" xmlns:nhin=\"http://www.hhs.gov/healthit/nhin\" policyid=\"12345678-1234-1234-1234-123456789abc\" rulecombiningalgid=\"urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable\"> " +
|
---|
52 | "<Description>Sample XACML policy showing access by user role</Description> " +
|
---|
53 | "<Target> " +
|
---|
54 | " <Actions> " +
|
---|
55 | " <Action> " +
|
---|
56 | " <ActionMatch MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\"> " +
|
---|
57 | " <AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#anyURI\"> " +
|
---|
58 | " http://www.hhs.gov/healthit/nhin#retrieveDocument " +
|
---|
59 | " </AttributeValue> " +
|
---|
60 | " <ActionAttributeDesignator AttributeId=\"urn:oasis:names:tc:xacml:2.0:action\" DataType=\"http://www.w3.org/2001/XMLSchema#anyURI\"> " +
|
---|
61 | " </ActionAttributeDesignator></ActionMatch> " +
|
---|
62 | " </Action>" +
|
---|
63 | " </Actions>" +
|
---|
64 | "" +
|
---|
65 | "</Target> " +
|
---|
66 | "<Environments>" +
|
---|
67 | " <Environment>" +
|
---|
68 | " <EnvironmentMatch MatchId=\"http://www.hhs.gov/healthit/nhin/function#instance-identifier-equal\">" +
|
---|
69 | " <AttributeValue DataType=\"http://www.hhs.gov/healthit/nhin#instance-identitifer\">" +
|
---|
70 | " <PatientId Root=\"\" Extension=\"\">" +
|
---|
71 | " </PatientId>" +
|
---|
72 | " </AttributeValue>" +
|
---|
73 | " <EnvironmentAttributeDesignator AttributeId=\"http://www.hhs.gov/healthit/nhin#subject-id\" DataType=\"http://www.hhs.gov/healthit/nhin#instance-identitifer\">" +
|
---|
74 | " </EnvironmentAttributeDesignator>" +
|
---|
75 | " </EnvironmentMatch>" +
|
---|
76 | " </Environment>" +
|
---|
77 | "</Environments>" +
|
---|
78 | "</Policy> ";
|
---|
79 |
|
---|
80 | public static boolean defaultOptIn() {
|
---|
81 | boolean optIn;
|
---|
82 |
|
---|
83 | try {
|
---|
84 | optIn = PropertyAccessor.getPropertyBoolean("gateway", "RetrieveDocdefaultOptIn");
|
---|
85 | } catch (Exception ex) {
|
---|
86 | optIn = false;
|
---|
87 | }
|
---|
88 |
|
---|
89 | return optIn;
|
---|
90 | }
|
---|
91 |
|
---|
92 | public static String DocumentToString(Document doc) {
|
---|
93 | String xmlString;
|
---|
94 |
|
---|
95 | //initialize StreamResult with File object to save to file
|
---|
96 | StreamResult result = new StreamResult(new StringWriter());
|
---|
97 | DOMSource source = new DOMSource(doc);
|
---|
98 | try {
|
---|
99 | Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
---|
100 | transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
---|
101 |
|
---|
102 | transformer.transform(source, result);
|
---|
103 | xmlString = result.getWriter().toString();
|
---|
104 | } catch (Exception ex) {
|
---|
105 | xmlString = "";
|
---|
106 | }
|
---|
107 |
|
---|
108 |
|
---|
109 | return xmlString;
|
---|
110 | }
|
---|
111 |
|
---|
112 | public static Document ByteArrayToDoc(byte[] rawData) {
|
---|
113 | Document doc = null;
|
---|
114 |
|
---|
115 | try {
|
---|
116 | DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
|
---|
117 | DocumentBuilder builder = builderFactory.newDocumentBuilder();
|
---|
118 |
|
---|
119 |
|
---|
120 | doc = builder.newDocument();
|
---|
121 | InputStream stream = new ByteArrayInputStream(rawData);
|
---|
122 |
|
---|
123 | doc = builder.parse(new InputSource(stream));
|
---|
124 | } catch (Exception ex) {
|
---|
125 | }
|
---|
126 |
|
---|
127 |
|
---|
128 | return doc;
|
---|
129 |
|
---|
130 | }
|
---|
131 |
|
---|
132 | public static Identifier extractPatientId(Document doc) {
|
---|
133 | Identifier id;
|
---|
134 | String orgId;
|
---|
135 | String patId;
|
---|
136 |
|
---|
137 | orgId = doc.getElementsByTagName("PatientId").item(0).getAttributes().getNamedItem("Root").getNodeValue();
|
---|
138 | patId = doc.getElementsByTagName("PatientId").item(0).getAttributes().getNamedItem("Extension").getNodeValue();
|
---|
139 |
|
---|
140 | id = new Identifier(patId, orgId);
|
---|
141 |
|
---|
142 | return id;
|
---|
143 |
|
---|
144 | }
|
---|
145 |
|
---|
146 | public static boolean isOptedIn(Document doc) {
|
---|
147 | Node rule = doc.getElementsByTagName(RULE_TAG).item(0);
|
---|
148 |
|
---|
149 | String ruleId = "";
|
---|
150 |
|
---|
151 | if (rule != null) {
|
---|
152 | ruleId = rule.getAttributes().getNamedItem(RULE_ID_ATTR).getNodeValue();
|
---|
153 | } else {
|
---|
154 | //If no cpp document exists for the patient, go with the site's
|
---|
155 | //default opt in value.
|
---|
156 | if (defaultOptIn()) {
|
---|
157 | ruleId = OPT_IN_RULE_ID;
|
---|
158 | }
|
---|
159 | }
|
---|
160 |
|
---|
161 | return (ruleId.equals(OPT_IN_RULE_ID));
|
---|
162 |
|
---|
163 | }
|
---|
164 |
|
---|
165 | public static boolean isOptedIn(String patId, String orgId) {
|
---|
166 | CPPOperations ops = new CPPOperations();
|
---|
167 | gov.hhs.fha.nhinc.repository.model.Document cppDoc;
|
---|
168 | boolean optedIn = false;
|
---|
169 |
|
---|
170 | cppDoc = ops.retreiveCPP(patId, orgId);
|
---|
171 |
|
---|
172 | if (cppDoc != null) {
|
---|
173 | if (cppDoc.getRawData() != null) {
|
---|
174 | optedIn = isOptedIn(ByteArrayToDoc(cppDoc.getRawData()));
|
---|
175 | } else {
|
---|
176 | optedIn = defaultOptIn();
|
---|
177 | }
|
---|
178 | } else {
|
---|
179 | //If no cpp document exists for the patient, go with the site's
|
---|
180 | //default opt in value.
|
---|
181 | optedIn = defaultOptIn();
|
---|
182 | }
|
---|
183 |
|
---|
184 | return optedIn;
|
---|
185 |
|
---|
186 | }
|
---|
187 |
|
---|
188 | public static void Save(Patients pats) {
|
---|
189 | for (Patient pat : pats) {
|
---|
190 | Save(pat);
|
---|
191 | }
|
---|
192 |
|
---|
193 | }
|
---|
194 |
|
---|
195 | public static void Save(Patient pat) {
|
---|
196 | Document doc = createXAML(pat);
|
---|
197 | String xacml = DocumentToString(doc);
|
---|
198 |
|
---|
199 | CPPOperations ops = new CPPOperations();
|
---|
200 | ops.init(pat.getIdentifiers().get(0).getId(), pat.getIdentifiers().get(0).getOrganizationId(), xacml);
|
---|
201 | ops.start();
|
---|
202 |
|
---|
203 | // Check for the results of sending the subscribe message from the thread
|
---|
204 | boolean resultsReceived = false;
|
---|
205 | boolean sendSuccess = false;
|
---|
206 | int waitCount = 0;
|
---|
207 | while (!resultsReceived && (waitCount < SEND_SLEEP_COUNT)) {
|
---|
208 | if (ops.isFinished()) {
|
---|
209 | resultsReceived = true;
|
---|
210 | sendSuccess = ops.isSendSuccessful();
|
---|
211 | if (log.isDebugEnabled()) {
|
---|
212 | log.debug("Subscribe send results received: " + sendSuccess);
|
---|
213 | }
|
---|
214 | } else {
|
---|
215 | if (log.isDebugEnabled()) {
|
---|
216 | log.debug("Subscribe send not completed - waiting for results - loop index: " + waitCount);
|
---|
217 | }
|
---|
218 | try {
|
---|
219 | Thread.sleep(SEND_SLEEP_TIME_MS);
|
---|
220 | } catch (Throwable t) {
|
---|
221 | // Eat error and continue
|
---|
222 | }
|
---|
223 | }
|
---|
224 | waitCount++;
|
---|
225 | }
|
---|
226 | }
|
---|
227 |
|
---|
228 | public static Document[] createXAML(Patients pats) {
|
---|
229 | Document[] docs = new Document[pats.size()];
|
---|
230 |
|
---|
231 | for (int x = 0; x < pats.size(); x++) {
|
---|
232 | docs[x] = createXAML(pats.get(x));
|
---|
233 | }
|
---|
234 | return docs;
|
---|
235 | }
|
---|
236 |
|
---|
237 | public static Document createXAML(Patient p) {
|
---|
238 | Document doc = null;
|
---|
239 |
|
---|
240 | try {
|
---|
241 | DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
|
---|
242 | DocumentBuilder builder = builderFactory.newDocumentBuilder();
|
---|
243 |
|
---|
244 | //doc = builder.parse (new org.xml.sax.InputSource ("\\src\\java\\gov\\hhs\\fha\\nhinc\\xaml\\basePolicy.xml"));
|
---|
245 | doc = builder.newDocument();
|
---|
246 | StringReader reader = new StringReader(basePolicy);
|
---|
247 | doc = builder.parse(new InputSource(reader));
|
---|
248 |
|
---|
249 | builder.parse(new InputSource(new StringReader(basePolicy)));
|
---|
250 |
|
---|
251 | doc = populatePatientInfo(doc, p);
|
---|
252 |
|
---|
253 |
|
---|
254 | Element rule = populateOptInOut(doc, p);
|
---|
255 |
|
---|
256 |
|
---|
257 | doc.getFirstChild().appendChild(rule);
|
---|
258 | doc.setXmlStandalone(true);
|
---|
259 | doc.normalizeDocument();
|
---|
260 |
|
---|
261 |
|
---|
262 | } catch (Exception ex) {
|
---|
263 | String error = ex.getMessage();
|
---|
264 | }
|
---|
265 |
|
---|
266 |
|
---|
267 | return doc;
|
---|
268 | }
|
---|
269 |
|
---|
270 | private static Document populatePatientInfo(Document doc, Patient p) {
|
---|
271 | Node pat = doc.getElementsByTagName("PatientId").item(0);
|
---|
272 | Identifier id = p.getIdentifiers().get(0);
|
---|
273 |
|
---|
274 | pat.getAttributes().getNamedItem("Root").setNodeValue(id.getOrganizationId());
|
---|
275 | pat.getAttributes().getNamedItem("Extension").setNodeValue(id.getId());
|
---|
276 |
|
---|
277 |
|
---|
278 | return doc;
|
---|
279 | }
|
---|
280 |
|
---|
281 | private static Element populateOptInOut(Document doc, Patient p) {
|
---|
282 | if (p.isOptedIn()) {
|
---|
283 | return populateOptIn(doc);
|
---|
284 | } else {
|
---|
285 | return populateOptOut(doc);
|
---|
286 | }
|
---|
287 | }
|
---|
288 |
|
---|
289 | private static Element populateOptOut(Document doc) {
|
---|
290 | Element optOut = doc.createElement(RULE_TAG);
|
---|
291 | optOut.setAttribute(RULE_ID_ATTR, OPT_OUT_RULE_ID);
|
---|
292 | optOut.setAttribute(RULE_EFFECT_ATTR, OPT_OUT_EFFECT);
|
---|
293 |
|
---|
294 | Element descr = doc.createElement("Description");
|
---|
295 | descr.setTextContent(DENY_DESCR);
|
---|
296 | optOut.appendChild(descr);
|
---|
297 | optOut.appendChild(doc.createElement("Target"));
|
---|
298 |
|
---|
299 | return optOut;
|
---|
300 | }
|
---|
301 |
|
---|
302 | private static Element populateOptIn(Document doc) {
|
---|
303 | Element optIN = doc.createElement(RULE_TAG);
|
---|
304 | optIN.setAttribute(RULE_ID_ATTR, OPT_IN_RULE_ID);
|
---|
305 | optIN.setAttribute(RULE_EFFECT_ATTR, OPT_IN_EFFECT);
|
---|
306 |
|
---|
307 | Element descr = doc.createElement("Description");
|
---|
308 | descr.setTextContent(PERMIT_DESCR);
|
---|
309 |
|
---|
310 | optIN.appendChild(descr);
|
---|
311 | optIN.appendChild(doc.createElement("Target"));
|
---|
312 |
|
---|
313 | return optIN;
|
---|
314 | }
|
---|
315 | }
|
---|
316 |
|
---|