1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 package org.apache.openoffice.ooxml.schema.automaton; 23 24 import java.util.HashMap; 25 import java.util.HashSet; 26 import java.util.Map; 27 import java.util.Set; 28 import java.util.TreeSet; 29 import java.util.Vector; 30 31 import org.apache.openoffice.ooxml.schema.model.base.QualifiedName; 32 33 /** Represents the set of states of a single complex type. 34 * 35 * Because states have to be unique, the state container is an object shared 36 * by all StateContext objects. 37 * 38 * There is a single start state but there can be more than one accepting state. 39 */ 40 public class StateContext 41 { StateContext( final StateContainer aStateContainer, final String sBaseStateName)42 public StateContext ( 43 final StateContainer aStateContainer, 44 final String sBaseStateName) 45 { 46 maStateContainer = aStateContainer; 47 maStates = new HashSet<>(); 48 maStartState = GetOrCreateState(new QualifiedName(null, null, sBaseStateName), null); 49 maDisambiguateCounters = new HashMap<>(); 50 } 51 52 53 54 CreateState( final QualifiedName aBasename, final String sSuffix)55 public State CreateState ( 56 final QualifiedName aBasename, 57 final String sSuffix) 58 { 59 final String sFullname = State.GetStateName(aBasename, sSuffix); 60 if (HasState(sFullname)) 61 throw new RuntimeException("state with name '"+sFullname+"' can not be created because it already exists"); 62 final State aState = new State(aBasename, sSuffix); 63 AddState(aState); 64 return aState; 65 } 66 67 68 CreateState(final String sBasename)69 public State CreateState (final String sBasename) 70 { 71 return CreateState(new QualifiedName(sBasename), null); 72 } 73 74 75 76 CreateState( final State aState, final String sSuffix)77 public State CreateState ( 78 final State aState, 79 final String sSuffix) 80 { 81 if (sSuffix==null && aState.GetSuffix()==null) 82 return CreateState(aState.GetBasename(), null); 83 else if (sSuffix!=null && aState.GetSuffix()!=null) 84 return CreateState(aState.GetBasename(), aState.GetSuffix()+"_"+sSuffix); 85 else if (sSuffix != null) 86 return CreateState(aState.GetBasename(), sSuffix); 87 else 88 return CreateState(aState.GetBasename(), aState.GetSuffix()); 89 } 90 91 92 93 GetState( final QualifiedName aBasename, final String sSuffix)94 public State GetState ( 95 final QualifiedName aBasename, 96 final String sSuffix) 97 { 98 return maStateContainer.GetStateForFullname(State.GetStateName(aBasename, sSuffix)); 99 } 100 101 102 103 GetOrCreateState( final QualifiedName aBasename, final String sSuffix)104 public State GetOrCreateState ( 105 final QualifiedName aBasename, 106 final String sSuffix) 107 { 108 State aState = GetState(aBasename, sSuffix); 109 if (aState == null) 110 { 111 aState = CreateState(aBasename, sSuffix); 112 AddState(aState); 113 } 114 return aState; 115 } 116 117 118 119 GetStartStateForTypeName(final QualifiedName aName)120 public State GetStartStateForTypeName (final QualifiedName aName) 121 { 122 return GetOrCreateState(aName, null); 123 } 124 125 126 127 CreateEndState()128 public State CreateEndState () 129 { 130 final State aEndState = CreateState( 131 maStartState.GetBasename(), 132 "end"); 133 aEndState.SetIsAccepting(); 134 return aEndState; 135 } 136 137 138 139 /** Some algorithms can not easily produce unique suffixes. 140 * Append an integer to the given suffix so that it becomes unique. 141 */ GetUnambiguousSuffix(final QualifiedName aBasename, final String sSuffix)142 public String GetUnambiguousSuffix (final QualifiedName aBasename, final String sSuffix) 143 { 144 String sStateName = State.GetStateName(aBasename, sSuffix); 145 if ( ! HasState(sStateName)) 146 { 147 // The given suffix can be used without modification. 148 return sSuffix; 149 } 150 else 151 { 152 int nIndex = 2; 153 final Integer nDisambiguateCounter = maDisambiguateCounters.get(sStateName); 154 if (nDisambiguateCounter != null) 155 nIndex = nDisambiguateCounter+1; 156 maDisambiguateCounters.put(sStateName, nIndex); 157 158 return sSuffix + "_" + nIndex; 159 } 160 } 161 162 163 164 HasState( final QualifiedName aBasename, final String sSuffix)165 public boolean HasState ( 166 final QualifiedName aBasename, 167 final String sSuffix) 168 { 169 return maStateContainer.HasState(State.GetStateName(aBasename, sSuffix)); 170 } 171 172 173 174 175 /** Return whether a state with the given name already belongs to the state 176 * context. 177 */ HasState(final String sFullname)178 public boolean HasState (final String sFullname) 179 { 180 return maStateContainer.HasState(sFullname); 181 } 182 183 184 185 186 /** The start state is the state a parser is in initially. 187 */ GetStartState()188 public State GetStartState () 189 { 190 return maStartState; 191 } 192 193 194 195 GetAcceptingStates()196 public Iterable<State> GetAcceptingStates () 197 { 198 final Vector<State> aAcceptingStates = new Vector<>(); 199 for (final State aState : maStates) 200 if (aState.IsAccepting()) 201 aAcceptingStates.add(aState); 202 return aAcceptingStates; 203 } 204 205 206 207 208 /** Add the given state to the state context. 209 */ AddState(final State aState)210 public void AddState (final State aState) 211 { 212 maStateContainer.AddState(aState); 213 maStates.add(aState); 214 } 215 216 217 218 RemoveState(final State aState)219 public void RemoveState (final State aState) 220 { 221 maStateContainer.RemoveState(aState); 222 maStates.remove(aState); 223 } 224 225 226 227 GetStateCount()228 public int GetStateCount () 229 { 230 return maStates.size(); 231 } 232 233 234 235 GetStatesSorted()236 public Iterable<State> GetStatesSorted() 237 { 238 final Set<State> aSortedStates = new TreeSet<>(); 239 aSortedStates.addAll(maStates); 240 return aSortedStates; 241 } 242 243 244 245 GetStates()246 public Iterable<State> GetStates() 247 { 248 return maStates; 249 } 250 251 252 253 GetTransitionCount()254 public int GetTransitionCount () 255 { 256 int nStateCount = 0; 257 for (final State aState : maStates) 258 nStateCount += aState.GetTransitionCount(); 259 return nStateCount; 260 } 261 262 263 264 265 private final StateContainer maStateContainer; 266 private final Set<State> maStates; 267 private final State maStartState; 268 private final Map<String,Integer> maDisambiguateCounters; 269 } 270