001 /** 002 * The contents of this file are subject to the Mozilla Public License Version 1.1 003 * (the "License"); you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at http://www.mozilla.org/MPL/ 005 * Software distributed under the License is distributed on an "AS IS" basis, 006 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 007 * specific language governing rights and limitations under the License. 008 * 009 * The Original Code is "SegmentFinder.java". Description: 010 * "A tool for getting segments by name within a message or part of a message." 011 * 012 * The Initial Developer of the Original Code is University Health Network. Copyright (C) 013 * 2002. All Rights Reserved. 014 * 015 * Contributor(s): ______________________________________. 016 * 017 * Alternatively, the contents of this file may be used under the terms of the 018 * GNU General Public License (the ?GPL?), in which case the provisions of the GPL are 019 * applicable instead of those above. If you wish to allow use of your version of this 020 * file only under the terms of the GPL and not to allow others to use your version 021 * of this file under the MPL, indicate your decision by deleting the provisions above 022 * and replace them with the notice and other provisions required by the GPL License. 023 * If you do not delete the provisions above, a recipient may use your version of 024 * this file under either the MPL or the GPL. 025 * 026 */ 027 028 package ca.uhn.hl7v2.util; 029 030 import ca.uhn.hl7v2.model.*; 031 import ca.uhn.hl7v2.HL7Exception; 032 import java.util.regex.*; 033 034 /** 035 * A tool for getting segments by name within a message or part of a message. 036 * @author Bryan Tripp 037 */ 038 public class SegmentFinder extends MessageNavigator { 039 040 /** 041 * Creates a new instance of SegmentFinder. 042 * @param root the scope of searches -- may be a whole message or only a branch 043 */ 044 public SegmentFinder(Group root) { 045 super(root); 046 } 047 048 /** 049 * Returns the first segment with a name that matches the given pattern, in a depth-first search. 050 * Repeated searches are initiated from the location just AFTER where the last segment was found. 051 * Call reset() is this is not desired. Note: this means that the current location will not be found. 052 * @param segmentName the name of the segment to find. The wildcad * means any number 053 * of arbitrary characters; the wildard ? one arbitrary character 054 * (eg "P*" or "*ID" or "???" or "P??" would match on PID). 055 * @param rep the repetition of the segment to return 056 */ 057 public Segment findSegment(String namePattern, int rep) throws HL7Exception { 058 Structure s = null; 059 do { 060 s = findStructure(namePattern, rep); 061 } while (!Segment.class.isAssignableFrom(s.getClass())); 062 return (Segment) s; 063 } 064 065 /** 066 * As findSegment(), but will only return a group. 067 */ 068 public Group findGroup(String namePattern, int rep) throws HL7Exception { 069 Structure s = null; 070 do { 071 s = findStructure(namePattern, rep); 072 } while (!Group.class.isAssignableFrom(s.getClass())); 073 return (Group) s; 074 } 075 076 /** 077 * Returns the first matching structure AFTER the current position 078 */ 079 private Structure findStructure(String namePattern, int rep) throws HL7Exception { 080 Structure s = null; 081 082 while (s == null) { 083 iterate(false, false); 084 String currentName = getCurrentStructure(0).getName(); 085 if (matches(namePattern, currentName)) { 086 s = getCurrentStructure(rep); 087 } 088 } 089 return s; 090 } 091 092 /** 093 * Returns the first segment with a name matching the given pattern that is a sibling of 094 * the structure at the current location. Other parts of the message are 095 * not searched (in contrast to findSegment). 096 * As a special case, if the pointer is at the root, the children of the root 097 * are searched. 098 * @param segmentName the name of the segment to get. The wildcad * means any number 099 * of arbitrary characters; the wildard ? one arbitrary character 100 * (eg "P*" or "*ID" or "???" or "P??" would match on PID). 101 * @param rep the repetition of the segment to return 102 */ 103 public Segment getSegment(String namePattern, int rep) throws HL7Exception { 104 Structure s = getStructure(namePattern, rep); 105 if (!Segment.class.isAssignableFrom(s.getClass())) { 106 throw new HL7Exception(s.getName() + " is not a segment", HL7Exception.APPLICATION_INTERNAL_ERROR); 107 } 108 return (Segment) s; 109 } 110 111 /** 112 * As getSegment() but will only return a group. 113 */ 114 public Group getGroup(String namePattern, int rep) throws HL7Exception { 115 Structure s = getStructure(namePattern, rep); 116 if (!Group.class.isAssignableFrom(s.getClass())) { 117 throw new HL7Exception(s.getName() + " is not a group", HL7Exception.APPLICATION_INTERNAL_ERROR); 118 } 119 return (Group) s; 120 } 121 122 private Structure getStructure(String namePattern, int rep) throws HL7Exception { 123 Structure s = null; 124 125 if (getCurrentStructure(0).equals(this.getRoot())) 126 drillDown(0); 127 128 String[] names = getCurrentStructure(0).getParent().getNames(); 129 for (int i = 0; i < names.length && s == null; i++) { 130 if (matches(namePattern, names[i])) { 131 toChild(i); 132 s = getCurrentStructure(rep); 133 } 134 } 135 136 if (s == null) 137 throw new HL7Exception("Can't find " + namePattern + " as a direct child", HL7Exception.APPLICATION_INTERNAL_ERROR); 138 139 return s; 140 } 141 142 /** 143 * Tests whether the given name matches the given pattern. 144 */ 145 /*private boolean matches(String pattern, String candidate) { 146 boolean matches = false; 147 boolean substring = false; 148 if (pattern.substring(0, 1).equals("*")) { 149 substring = true; 150 pattern = pattern.substring(1); 151 } 152 153 if (substring && (candidate.indexOf(pattern) >= 0)) { 154 matches = true; 155 } else if (!substring && candidate.equals(pattern)) { 156 matches = true; 157 } 158 return matches; 159 }*/ 160 161 /** 162 * Tests whether the given name matches the given pattern. 163 */ 164 private boolean matches(String pattern, String candidate) { 165 //shortcut ... 166 if (pattern.equals(candidate)) { 167 return true; 168 } 169 170 if (!Pattern.matches("[\\w\\*\\?]*", pattern)) 171 throw new IllegalArgumentException("The pattern " + pattern + " is not valid. Only [\\w\\*\\?]* allowed."); 172 173 pattern = Pattern.compile("\\*").matcher(pattern).replaceAll(".*"); 174 pattern = Pattern.compile("\\?").matcher(pattern).replaceAll("."); 175 176 return Pattern.matches(pattern, candidate); 177 } 178 }