View Javadoc
1   /*
2    * Copyright 2006 Werner Guttmann, Ralf Joachim
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package org.exolab.castor.builder.conflictresolution;
15  
16  import java.util.Enumeration;
17  
18  import org.exolab.castor.builder.SGStateInfo;
19  import org.exolab.castor.builder.binding.XPathHelper;
20  import org.exolab.castor.builder.info.ClassInfo;
21  import org.exolab.castor.builder.info.nature.XMLInfoNature;
22  import org.exolab.castor.util.dialog.ConsoleDialog;
23  import org.exolab.castor.xml.schema.Annotated;
24  import org.exolab.castor.xml.schema.SchemaNames;
25  import org.exolab.javasource.JClass;
26  
27  /**
28   * An implementation of {@link ClassNameCRStrategy} that reports any conflict notifications to a
29   * console dialog, asking the user whether to stop code generation (as the conflict is not
30   * acceptable), or whether to proceed by overwriting an already existing class.
31   *
32   * @author <a href="mailto:werner DOT guttmann AT gmx DOT net">Werner Guttmann</a>
33   * @since 1.1
34   */
35  public final class WarningViaDialogClassNameCRStrategy extends BaseClassNameCRStrategy
36      implements ClassNameCRStrategy {
37  
38    /**
39     * Name of this strategy.
40     */
41    public static final String NAME = "warnViaConsoleDialog";
42  
43    /**
44     * The {@link ConsoleDialog} instance to use for output.
45     */
46    private ConsoleDialog _dialog;
47  
48    /**
49     * Creates an instance of this name conflict resolution strategy, that will use the specified
50     * {@link ConsoleDialog} instance to emit warnings to the user and ask about an approach to deal
51     * with them.
52     */
53    public WarningViaDialogClassNameCRStrategy() {
54      // Nothing to do.
55    }
56  
57    /**
58     * Handle a class name conflict between newClassInfo and conflict.
59     *
60     * @param state SourceGeneration state
61     * @param newClassInfo ClassInfo for the new class
62     * @param conflict JClass for the existing class
63     * @return the provided source generator state, as modified by the strategy
64     * @see org.exolab.castor.builder.conflictresolution.ClassNameCRStrategy
65     *      #dealWithClassNameConflict(org.exolab.castor.builder.SGStateInfo,
66     *      org.exolab.castor.builder.info.ClassInfo, org.exolab.javasource.JClass)
67     */
68    public SGStateInfo dealWithClassNameConflict(final SGStateInfo state,
69        final ClassInfo newClassInfo, final JClass conflict) {
70      if (!state.getSuppressNonFatalWarnings()) {
71        // -- if the ClassInfo are equal, we can just return
72        ClassInfo oldClassInfo = state.resolve(conflict);
73        if (oldClassInfo == newClassInfo) {
74          return state;
75        }
76  
77        // -- Find the Schema structures that are conflicting
78        Annotated a1 = null;
79        Annotated a2 = null;
80  
81        // Loop until we exhaust the Enumeration or until we have found both
82        Enumeration enumeration = state.keys();
83        while (enumeration.hasMoreElements() && (a1 == null || a2 == null)) {
84          Object key = enumeration.nextElement();
85          if (!(key instanceof Annotated)) {
86            continue;
87          }
88  
89          ClassInfo cInfo = state.resolve(key);
90          if (newClassInfo == cInfo) {
91            a1 = (Annotated) key;
92          } else if (oldClassInfo == cInfo) {
93            a2 = (Annotated) key;
94          }
95        }
96  
97        StringBuilder error = new StringBuilder(64);
98        error.append("Warning: A class name generation conflict has occured between ");
99        if (a1 != null) {
100         error.append(SchemaNames.getStructureName(a1));
101         error.append(" '");
102         error.append(XPathHelper.getSchemaLocation(a1));
103       } else {
104         if (newClassInfo.hasNature(XMLInfoNature.class.getName())) {
105           XMLInfoNature xmlNature = new XMLInfoNature(newClassInfo);
106           error.append(xmlNature.getNodeTypeName());
107           error.append(" '");
108           error.append(xmlNature.getNodeName());
109         }
110       }
111       error.append("' and ");
112       if (a2 != null) {
113         error.append(SchemaNames.getStructureName(a2));
114         error.append(" '");
115         error.append(XPathHelper.getSchemaLocation(a2));
116       } else {
117         if (oldClassInfo.hasNature(XMLInfoNature.class.getName())) {
118           XMLInfoNature xmlNature = new XMLInfoNature(oldClassInfo);
119           error.append(xmlNature.getNodeTypeName());
120           error.append(" '");
121           error.append(xmlNature.getNodeName());
122         }
123       }
124       error.append("'. Please use a Binding file to solve this problem.");
125       error.append("Continue anyway [not recommended] ");
126 
127       char ch = _dialog.confirm(error.toString(), "yn", "y = yes, n = no");
128       if (ch == 'n') {
129         state.setStatusCode(SGStateInfo.STOP_STATUS);
130       }
131     }
132     return state;
133   }
134 
135   /**
136    * Returns the name of the strategy.
137    * 
138    * @return the name of the strategy.
139    * @see org.exolab.castor.builder.conflictresolution.ClassNameCRStrategy#getName()
140    */
141   public String getName() {
142     return NAME;
143   }
144 
145   /**
146    * Sets the console dialog to use with this strategy.
147    *
148    * @param dialog the console dialog to use with this strategy.
149    * @see org.exolab.castor.builder.conflictresolution.ClassNameCRStrategy#
150    *      setConsoleDialog(org.exolab.castor.util.dialog.ConsoleDialog)
151    */
152   public void setConsoleDialog(final ConsoleDialog dialog) {
153     this._dialog = dialog;
154   }
155 
156   /**
157    * Presents the user with a console dialog, asking for confirmation whether an existing file
158    * should be overwritten (or not).
159    *
160    * @param filename the filename to potentially overwrite.
161    * @return whether or not the file should be overwritten.
162    *
163    * @see org.exolab.castor.builder.conflictresolution.ClassNameCRStrategy
164    *      #dealWithFileOverwrite(java.lang.String, boolean)
165    */
166   public boolean dealWithFileOverwrite(final String filename) {
167     boolean allowPrinting = true;
168 
169     String message = filename + " already exists. overwrite";
170     char ch = _dialog.confirm(message, "yna", "y = yes, n = no, a = all");
171     switch (ch) {
172       case 'a':
173         getSingleClassGenerator().setPromptForOverwrite(false);
174         allowPrinting = true;
175         break;
176       case 'y':
177         allowPrinting = true;
178         break;
179       default:
180         allowPrinting = false;
181         break;
182     }
183     return allowPrinting;
184   }
185 
186   /**
187    * Returns the {@link ConsoleDialog} instance in use.
188    * 
189    * @return the {@link ConsoleDialog} used for output/feedback gathering.
190    */
191   protected ConsoleDialog getConsoleDialog() {
192     return this._dialog;
193   }
194 
195 }