[507] | 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 |
|
---|