001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.core.reverseengineering.parsingfacilities;
043:
044: import java.util.Stack;
045:
046: import org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.translation.statehandlers.StateHandler;
047: import org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.translation.statehandlers.StatementFactory;
048: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IStateFilter;
049: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IStateListener;
050: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IStatePayload;
051: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenDescriptor;
052: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenFilter;
053: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenProcessor;
054: import org.netbeans.modules.uml.core.support.umlsupport.Log;
055:
056: /**
057: */
058: public class JavaOperationUMLParserProcessor implements
059: IJavaOperationUMLParserProcessor, IStateFilter, IStateListener,
060: ITokenProcessor, ITokenFilter, IOperationParserOptionsHandler {
061: /**
062: * ProcessState determines if a state is to be filtered or not.
063: *
064: * @param stateName [in] The name of the state.
065: * @param pVal [out] True if the state is to be processed, false otherwise.
066: */
067: public boolean processState(String stateName, String language) {
068: return true;
069: }
070:
071: /**
072: * The OnBeginState event is fired when the state of the parser has changed.
073: * A new state can begin while still in a state."
074: *
075: * @param stateName [in] The name of the state.
076: * @param payload [in] Extra data.
077: */
078: public void onBeginState(String stateName, String language,
079: IStatePayload Payload) {
080: addStateHandler(stateName, language);
081: }
082:
083: /**
084: * The OnEndState event will be fired when exiting a state.
085: *
086: * @param stateName [in] The name of the state.
087: */
088: public void onEndState(String stateName) {
089: removeStateHandler(stateName);
090: }
091:
092: private static int indent = 0;
093: private final boolean DEBUG = false;
094:
095: //used only debugging parser tree, or reacting to it.
096: private void echo(String s) {
097: if (DEBUG)
098: System.out.println(s);
099: }
100:
101: //used only debugging parser tree, or reacting to it.
102: //there are System.out.println method calls commented out. To see the
103: //tokens and States coming from the parser, uncomment these calls.
104: private synchronized String getIndent(int n) {
105: StringBuffer sb = new StringBuffer(n);
106: for (int i = 0; i < n; i++)
107: sb.append(" ");
108:
109: return sb.toString();
110: }
111:
112: //used only debugging parser tree, or reacting to it.
113: private synchronized int addIndent() {
114: return indent++;
115: }
116:
117: //used only debugging parser tree, or reacting to it.
118: private synchronized int removeIndent() {
119: return --indent;
120: }
121:
122: protected void addStateHandler(String stateName, String language) {
123: OperationHandlerData data = new OperationHandlerData();
124: data.stateName = stateName;
125: if (m_StateHandlers.size() > 0) {
126: OperationHandlerData handler = m_StateHandlers.peek();
127: if (handler.handler != null) {
128: data.handler = handler.handler.createSubStateHandler(
129: stateName, language);
130:
131: // I do not want to initialize the handler twice. So, if the returned
132: // handler is the same as the current handler (in other words
133: // CreateSubStateHandler returned the THIS pointe), then do not initialize
134: // the handler. The handler has already been initialized.
135: if (data.handler != handler.handler
136: && data.handler != null)
137: data.handler.initialize();
138: }
139:
140: // I always want to add the state handler to the list. Even
141: // if it is NULL. Pushing a NULL state handler on the stack
142: // is a way to filter out an entire state (and all of the
143: // tokens in the state).
144:
145: //debugging statement - only effective if local DEBUG is true. Used to echo
146: //parsing structure.
147: echo(getIndent(addIndent()) + "<" + stateName + " handler="
148: + getName(data) + ">");
149: m_StateHandlers.push(data);
150: } else {
151: data.handler = StatementFactory.retrieveStatementHandler(
152: stateName, language, getOptions(), m_SymbolTable);
153:
154: // I do not want to initialize the handler twice. So, if the returned
155: // handler is the same as the current handler (in other words
156: // CreateSubStateHandler returned the THIS pointe), then do not initialize
157: // the handler. The handler has already been initialized.
158: if (data.handler != null) {
159: data.handler.initialize();
160:
161: // I only want to add NON-NULL state handlers to the
162: // list.
163:
164: //debugging statement - only effective if local DEBUG is true. Used to echo
165: //parsing structure.
166: echo(getIndent(addIndent()) + "<" + stateName
167: + " handler=" + getName(data) + ">");
168: m_StateHandlers.push(data);
169: }
170: }
171: }
172:
173: /**
174: * Removes the current state from the controlled list of states.
175: *
176: * @param stateName [in] The name of the state.
177: */
178: protected void removeStateHandler(String stateName) {
179: if (m_StateHandlers.size() > 0) {
180: // Remove the hander from the stack and notify the handler that
181: // the state has ended.
182: OperationHandlerData oldData = m_StateHandlers.pop();
183:
184: //debugging statement - only effective if local DEBUG is true. Used to echo
185: //parsing structure.
186: echo(getIndent(removeIndent()) + "</" + stateName + ">");
187:
188: if (oldData.handler != null)
189: oldData.handler.stateComplete(stateName);
190: }
191: }
192:
193: private String getName(OperationHandlerData data) {
194: String res = data.handler == null ? "null" : data.handler
195: .getClass().getName();
196: int dot = res.lastIndexOf('.');
197: return res.substring(dot + 1);
198: }
199:
200: /**
201: * Removes all controlled states. The removed states will be
202: * notified.
203: */
204: protected void cleanUpStateHandlers() {
205: // Cycle through the states that have not been completed yet.
206: // Act as if they have beed completed. This wil force all
207: // data to be sent to the listeners. This should only occur
208: // if something terrible has happened while processing
209: // the source file. Example Stack Overflow error.
210: while (m_StateHandlers.size() > 0) {
211: OperationHandlerData data = m_StateHandlers.peek();
212: removeStateHandler(data.stateName);
213: }
214: }
215:
216: /**
217: * Process the token that has been discovered by the parser.
218: *
219: * pToken [in] The token to be processed.
220: */
221: public void processToken(ITokenDescriptor token, String language) {
222:
223: //the "echo" calls are debugging statements - only effective if local DEBUG is true. Used to echo
224: //parsing structure.
225: if (m_StateHandlers.size() > 0) {
226: try {
227: OperationHandlerData data = m_StateHandlers.peek();
228: if (data.handler != null) {
229: data.handler.processToken(token, language);
230: echo(getIndent(indent) + "<token value="
231: + token.getValue() + " handler="
232: + getName(data) + "/>");
233: } else
234: echo(getIndent(indent) + "<token value="
235: + token.getValue() + " handler="
236: + getName(data) + "/>");
237: } catch (Exception e) {
238: e.printStackTrace();
239: }
240: } else
241: echo(getIndent(indent) + "<token value=" + token.getValue()
242: + " handler=NO_STATE_HANDLER/>");
243: }
244:
245: /**
246: * The token filter implementation. Determines if the specified
247: * token should be processed by the token listener.
248: *
249: * @param tokenType [in] The token type.
250: * @param stateName [in] The name of the current state.
251: * @param language [in] The language that is being processed.
252: * @param pVal [in] The result.
253: */
254: public boolean isTokenValid(String tokenType, String stateName,
255: String language) {
256: return true;
257: }
258:
259: /* (non-Javadoc)
260: * @see org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.IOperationParserOptionsHandler#setOptions(org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.IOpParserOptions)
261: */
262: public void setOptions(IOpParserOptions options) {
263: m_ParserOptions = options;
264: }
265:
266: /* (non-Javadoc)
267: * @see org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.IOperationParserOptionsHandler#getOptions()
268: */
269: public IOpParserOptions getOptions() {
270: return m_ParserOptions;
271: }
272:
273: private static class OperationHandlerData {
274: public StateHandler handler;
275: public String stateName;
276: }
277:
278: private Stack<OperationHandlerData> m_StateHandlers = new Stack<OperationHandlerData>();
279: private IOpParserOptions m_ParserOptions;
280: private SymbolTable m_SymbolTable = new SymbolTable();
281: }
|