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-2006 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.spring.beans.hyperlink;
043:
044: import java.util.HashMap;
045: import java.util.Map;
046: import javax.swing.text.Document;
047: import org.netbeans.editor.BaseDocument;
048: import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider;
049: import org.netbeans.modules.spring.beans.editor.ContextUtilities;
050: import org.netbeans.modules.spring.beans.editor.DocumentContext;
051: import org.netbeans.modules.spring.beans.editor.SpringXMLConfigEditorUtils.Public;
052: import org.netbeans.modules.spring.beans.editor.SpringXMLConfigEditorUtils.Static;
053: import org.netbeans.modules.spring.beans.utils.StringUtils;
054: import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport;
055:
056: /**
057: * Provides hyperlinking functionality for Spring XML Configuration files
058: *
059: * @author Rohan Ranade
060: */
061: public class SpringXMLConfigHyperlinkProvider implements
062: HyperlinkProvider {
063:
064: private static final String P_NAMESPACE = "http://www.springframework.org/schema/p"; // NOI18N
065:
066: private static final String BEAN_TAG = "bean"; // NOI18N
067: private static final String IMPORT_TAG = "import"; // NOI18N
068: private static final String LOOKUP_METHOD_TAG = "lookup-method"; // NOI18N
069: private static final String REPLACED_METHOD_TAG = "replaced-method"; // NOI18N
070: private static final String PROPERTY_TAG = "property"; // NOI18N
071: private static final String ALIAS_TAG = "alias"; // NOI18N
072: private static final String CONSTRUCTOR_ARG_TAG = "constructor-arg"; // NOI18N
073: private static final String REF_TAG = "ref"; // NOI18N
074: private static final String IDREF_TAG = "idref"; // NOI18N
075:
076: private static final String CLASS_ATTRIB = "class"; // NOI18N
077: private static final String RESOURCE_ATTRIB = "resource"; // NOI18N
078: private static final String INIT_METHOD_ATTRIB = "init-method"; // NOI18N
079: private static final String DESTROY_METHOD_ATTRIB = "destroy-method"; // NOI18N
080: private static final String NAME_ATTRIB = "name"; // NOI18N
081: private static final String FACTORY_METHOD_ATTRIB = "factory-method"; // NOI18N
082: private static final String FACTORY_BEAN_ATTRIB = "factory-bean"; // NOI18N
083: private static final String DEPENDS_ON_ATTRIB = "depends-on"; // NOI18N
084: private static final String PARENT_ATTRIB = "parent"; // NOI18N
085: private static final String REPLACER_ATTRIB = "replacer"; // NOI18N
086: private static final String REF_ATTRIB = "ref"; // NOI18N
087: private static final String BEAN_ATTRIB = "bean"; // NOI18N
088: private static final String LOCAL_ATTRIB = "local"; // NOI18N
089:
090: private BaseDocument lastDocument;
091:
092: private HyperlinkProcessor currentProcessor;
093:
094: private Map<String, HyperlinkProcessor> attribValueProcessors = new HashMap<String, HyperlinkProcessor>();
095:
096: private PHyperlinkProcessor pHyperlinkProcessor = new PHyperlinkProcessor();
097:
098: public SpringXMLConfigHyperlinkProvider() {
099: this .lastDocument = null;
100:
101: JavaClassHyperlinkProcessor classHyperlinkProcessor = new JavaClassHyperlinkProcessor();
102: registerAttribValueHyperlinkPoint(BEAN_TAG, CLASS_ATTRIB,
103: classHyperlinkProcessor);
104:
105: JavaMethodHyperlinkProcessor methodHyperlinkProcessor = new JavaMethodHyperlinkProcessor(
106: Public.DONT_CARE, Static.NO, 0);
107: registerAttribValueHyperlinkPoint(BEAN_TAG, INIT_METHOD_ATTRIB,
108: methodHyperlinkProcessor);
109: registerAttribValueHyperlinkPoint(BEAN_TAG,
110: DESTROY_METHOD_ATTRIB, methodHyperlinkProcessor);
111:
112: FactoryMethodHyperlinkProcessor factoryMethodHyperlinkProcessor = new FactoryMethodHyperlinkProcessor();
113: registerAttribValueHyperlinkPoint(BEAN_TAG,
114: FACTORY_METHOD_ATTRIB, factoryMethodHyperlinkProcessor);
115:
116: methodHyperlinkProcessor = new JavaMethodHyperlinkProcessor(
117: Public.DONT_CARE, Static.NO, 0);
118: registerAttribValueHyperlinkPoint(LOOKUP_METHOD_TAG,
119: NAME_ATTRIB, methodHyperlinkProcessor);
120:
121: methodHyperlinkProcessor = new JavaMethodHyperlinkProcessor(
122: Public.DONT_CARE, Static.NO, -1);
123: registerAttribValueHyperlinkPoint(REPLACED_METHOD_TAG,
124: NAME_ATTRIB, methodHyperlinkProcessor);
125:
126: ResourceHyperlinkProcessor resourceHyperlinkProcessor = new ResourceHyperlinkProcessor();
127: registerAttribValueHyperlinkPoint(IMPORT_TAG, RESOURCE_ATTRIB,
128: resourceHyperlinkProcessor);
129:
130: PropertyHyperlinkProcessor propertyHyperlinkProcessor = new PropertyHyperlinkProcessor();
131: registerAttribValueHyperlinkPoint(PROPERTY_TAG, NAME_ATTRIB,
132: propertyHyperlinkProcessor);
133:
134: BeansRefHyperlinkProcessor beansRefHyperlinkProcessor = new BeansRefHyperlinkProcessor(
135: true);
136: registerAttribValueHyperlinkPoint(BEAN_TAG,
137: FACTORY_BEAN_ATTRIB, beansRefHyperlinkProcessor);
138: registerAttribValueHyperlinkPoint(BEAN_TAG, DEPENDS_ON_ATTRIB,
139: beansRefHyperlinkProcessor);
140: registerAttribValueHyperlinkPoint(BEAN_TAG, PARENT_ATTRIB,
141: beansRefHyperlinkProcessor);
142: registerAttribValueHyperlinkPoint(LOOKUP_METHOD_TAG,
143: BEAN_ATTRIB, beansRefHyperlinkProcessor);
144: registerAttribValueHyperlinkPoint(REPLACED_METHOD_TAG,
145: REPLACER_ATTRIB, beansRefHyperlinkProcessor);
146: registerAttribValueHyperlinkPoint(PROPERTY_TAG, REF_ATTRIB,
147: beansRefHyperlinkProcessor);
148: registerAttribValueHyperlinkPoint(ALIAS_TAG, NAME_ATTRIB,
149: beansRefHyperlinkProcessor);
150: registerAttribValueHyperlinkPoint(CONSTRUCTOR_ARG_TAG,
151: REF_ATTRIB, beansRefHyperlinkProcessor);
152: registerAttribValueHyperlinkPoint(REF_TAG, BEAN_ATTRIB,
153: beansRefHyperlinkProcessor);
154: registerAttribValueHyperlinkPoint(IDREF_TAG, BEAN_ATTRIB,
155: beansRefHyperlinkProcessor);
156:
157: beansRefHyperlinkProcessor = new BeansRefHyperlinkProcessor(
158: false);
159: registerAttribValueHyperlinkPoint(IDREF_TAG, LOCAL_ATTRIB,
160: beansRefHyperlinkProcessor);
161: registerAttribValueHyperlinkPoint(REF_TAG, LOCAL_ATTRIB,
162: beansRefHyperlinkProcessor);
163: }
164:
165: private void registerAttribValueHyperlinkPoint(String tagName,
166: String attribName, HyperlinkProcessor processor) {
167: attribValueProcessors.put(createRegisteredName(tagName,
168: attribName), processor);
169: }
170:
171: public boolean isHyperlinkPoint(Document document, int offset) {
172: if (!(document instanceof BaseDocument)) {
173: return false;
174: }
175:
176: BaseDocument doc = (BaseDocument) document;
177: if (!(doc.getSyntaxSupport() instanceof XMLSyntaxSupport)) {
178: return false;
179: }
180:
181: HyperlinkEnv env = new HyperlinkEnv(document, offset);
182: if (env.getType().isValueHyperlink()) {
183: currentProcessor = locateHyperlinkProcessor(env
184: .getTagName(), env.getAttribName(),
185: attribValueProcessors);
186: if (currentProcessor == null
187: && isPNamespaceName(env.getDocumentContext(), env
188: .getAttribName())) {
189: currentProcessor = pHyperlinkProcessor;
190: }
191: } else if (env.getType().isAttributeHyperlink()) {
192: if (isPNamespaceName(env.getDocumentContext(), env
193: .getAttribName())) {
194: currentProcessor = pHyperlinkProcessor;
195: } else {
196: currentProcessor = null;
197: }
198: } else {
199: currentProcessor = null;
200: }
201:
202: return currentProcessor != null;
203: }
204:
205: public int[] getHyperlinkSpan(Document document, int offset) {
206: if (!(document instanceof BaseDocument)) {
207: return null;
208: }
209:
210: if (currentProcessor == null) {
211: return null;
212: }
213:
214: HyperlinkEnv env = new HyperlinkEnv(document, offset);
215: return currentProcessor.getSpan(env);
216: }
217:
218: public void performClickAction(Document document, int offset) {
219: HyperlinkEnv env = new HyperlinkEnv(document, offset);
220: if (currentProcessor != null) {
221: currentProcessor.process(env);
222: }
223: }
224:
225: protected String createRegisteredName(String nodeName,
226: String attributeName) {
227: StringBuilder builder = new StringBuilder();
228: if (StringUtils.hasText(nodeName)) {
229: builder.append("/nodeName="); // NOI18N
230: builder.append(nodeName);
231: } else {
232: builder.append("/nodeName="); // NOI18N
233: builder.append("*"); // NOI18N
234: }
235:
236: if (StringUtils.hasText(attributeName)) {
237: builder.append("/attribute="); // NOI18N
238: builder.append(attributeName);
239: }
240:
241: return builder.toString();
242: }
243:
244: private HyperlinkProcessor locateHyperlinkProcessor(
245: String nodeName, String attributeName,
246: Map<String, HyperlinkProcessor> processors) {
247: String key = createRegisteredName(nodeName, attributeName);
248: if (processors.containsKey(key)) {
249: return processors.get(key);
250: }
251:
252: key = createRegisteredName("*", attributeName); // NOI18N
253: if (processors.containsKey(key)) {
254: return processors.get(key);
255: }
256:
257: return null;
258: }
259:
260: private boolean isPNamespaceName(DocumentContext context,
261: String nodeName) {
262: String prefix = ContextUtilities
263: .getPrefixFromNodeName(nodeName);
264: if (prefix != null) {
265: String namespaceUri = context.lookupNamespacePrefix(prefix);
266: if (P_NAMESPACE.equals(namespaceUri)) {
267: return true;
268: }
269: }
270: return false;
271: }
272: }
|