1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package org.eclipse.jdt.internal.ui.preferences.formatter;
14 import java.io.ByteArrayInputStream;
15 import java.io.ByteArrayOutputStream;
17 import java.io.FileInputStream;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.io.UnsupportedEncodingException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
33 import javax.xml.parsers.SAXParser;
34 import javax.xml.parsers.SAXParserFactory;
35 import javax.xml.transform.OutputKeys;
36 import javax.xml.transform.Transformer;
37 import javax.xml.transform.TransformerException;
38 import javax.xml.transform.TransformerFactory;
39 import javax.xml.transform.dom.DOMSource;
40 import javax.xml.transform.stream.StreamResult;
42 import org.xml.sax.Attributes;
43 import org.xml.sax.InputSource;
44 import org.xml.sax.SAXException;
45 import org.xml.sax.helpers.DefaultHandler;
47 import org.w3c.dom.Document;
48 import org.w3c.dom.Element;
50 import org.eclipse.core.runtime.CoreException;
51 import org.eclipse.core.runtime.IStatus;
52 import org.eclipse.core.runtime.preferences.DefaultScope;
53 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
54 import org.eclipse.core.runtime.preferences.IScopeContext;
56 import org.eclipse.jdt.ui.JavaUI;
58 import org.eclipse.jdt.internal.ui.JavaPlugin;
59 import org.eclipse.jdt.internal.ui.JavaUIException;
60 import org.eclipse.jdt.internal.ui.JavaUIStatus;
61 import org.eclipse.jdt.internal.ui.preferences.formatter.ProfileManager.CustomProfile;
62 import org.eclipse.jdt.internal.ui.preferences.formatter.ProfileManager.Profile;
66 * Can load/store profiles from/to profilesKey
68 public class ProfileStore {
70 /** The default encoding to use */
71 public static final String ENCODING= "UTF-8"; //$NON-NLS-1$
73 protected static final String VERSION_KEY_SUFFIX= ".version"; //$NON-NLS-1$
76 * A SAX event handler to parse the xml format for profiles.
78 private final static class ProfileDefaultHandler extends DefaultHandler {
80 private List<Profile> fProfiles;
84 private Map<String, String> fSettings;
88 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
90 if (qName.equals(XML_NODE_SETTING)) {
92 final String key= attributes.getValue(XML_ATTRIBUTE_ID);
93 final String value= attributes.getValue(XML_ATTRIBUTE_VALUE);
94 fSettings.put(key, value);
96 } else if (qName.equals(XML_NODE_PROFILE)) {
98 fName= attributes.getValue(XML_ATTRIBUTE_NAME);
99 fKind= attributes.getValue(XML_ATTRIBUTE_PROFILE_KIND);
100 if (fKind == null) //Can only be an CodeFormatterProfile created pre 3.3M2
101 fKind= ProfileVersioner.CODE_FORMATTER_PROFILE_KIND;
103 fSettings= new HashMap<String, String>(200);
106 else if (qName.equals(XML_NODE_ROOT)) {
108 fProfiles= new ArrayList<Profile>();
110 fVersion= Integer.parseInt(attributes.getValue(XML_ATTRIBUTE_VERSION));
111 } catch (NumberFormatException ex) {
112 throw new SAXException(ex);
119 public void endElement(String uri, String localName, String qName) {
120 if (qName.equals(XML_NODE_PROFILE)) {
121 fProfiles.add(new CustomProfile(fName, fSettings, fVersion, fKind));
128 public List<Profile> getProfiles() {
135 * Identifiers for the XML file.
137 private final static String XML_NODE_ROOT= "profiles"; //$NON-NLS-1$
138 private final static String XML_NODE_PROFILE= "profile"; //$NON-NLS-1$
139 private final static String XML_NODE_SETTING= "setting"; //$NON-NLS-1$
141 private final static String XML_ATTRIBUTE_VERSION= "version"; //$NON-NLS-1$
142 private final static String XML_ATTRIBUTE_ID= "id"; //$NON-NLS-1$
143 private final static String XML_ATTRIBUTE_NAME= "name"; //$NON-NLS-1$
144 private final static String XML_ATTRIBUTE_PROFILE_KIND= "kind"; //$NON-NLS-1$
145 private final static String XML_ATTRIBUTE_VALUE= "value"; //$NON-NLS-1$
147 private final IProfileVersioner fProfileVersioner;
148 private final String fProfilesKey;
149 private final String fProfilesVersionKey;
152 public ProfileStore(String profilesKey, IProfileVersioner profileVersioner) {
153 fProfilesKey= profilesKey;
154 fProfileVersioner= profileVersioner;
155 fProfilesVersionKey= profilesKey + VERSION_KEY_SUFFIX;
159 * @return Returns the collection of profiles currently stored in the preference store or
160 * <code>null</code> if the loading failed. The elements are of type {@link ProfileManager.CustomProfile}
161 * and are all updated to the latest version.
162 * @throws CoreException
164 public List<Profile> readProfiles(IScopeContext scope) throws CoreException {
165 return readProfilesFromString(scope.getNode(JavaUI.ID_PLUGIN).get(fProfilesKey, null));
168 public void writeProfiles(Collection<Profile> profiles, IScopeContext instanceScope) throws CoreException {
169 ByteArrayOutputStream stream= new ByteArrayOutputStream(2000);
171 writeProfilesToStream(profiles, stream, ENCODING, fProfileVersioner);
174 val= stream.toString(ENCODING);
175 } catch (UnsupportedEncodingException e) {
176 val= stream.toString();
178 IEclipsePreferences uiPreferences = instanceScope.getNode(JavaUI.ID_PLUGIN);
179 uiPreferences.put(fProfilesKey, val);
180 uiPreferences.putInt(fProfilesVersionKey, fProfileVersioner.getCurrentVersion());
182 try { stream.close(); } catch (IOException e) { /* ignore */ }
186 public List<Profile> readProfilesFromString(String profiles) throws CoreException {
187 if (profiles != null && profiles.length() > 0) {
190 bytes= profiles.getBytes(ENCODING);
191 } catch (UnsupportedEncodingException e) {
192 bytes= profiles.getBytes();
194 InputStream is= new ByteArrayInputStream(bytes);
196 List<Profile> res= readProfilesFromStream(new InputSource(is));
198 for (int i= 0; i < res.size(); i++) {
199 fProfileVersioner.update((CustomProfile) res.get(i));
204 try { is.close(); } catch (IOException e) { /* ignore */ }
212 * Read the available profiles from the internal XML file and return them
213 * as collection or <code>null</code> if the file is not a profile file.
214 * @param file The file to read from
215 * @return returns a list of <code>CustomProfile</code> or <code>null</code>
216 * @throws CoreException
218 public List<Profile> readProfilesFromFile(File file) throws CoreException {
220 final FileInputStream reader= new FileInputStream(file);
222 return readProfilesFromStream(new InputSource(reader));
224 try { reader.close(); } catch (IOException e) { /* ignore */ }
226 } catch (IOException e) {
227 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_reading_xml_message);
232 * Load profiles from a XML stream and add them to a map or <code>null</code> if the source is not a profile store.
233 * @param inputSource The input stream
234 * @return returns a list of <code>CustomProfile</code> or <code>null</code>
235 * @throws CoreException
237 public static List<Profile> readProfilesFromStream(InputSource inputSource) throws CoreException {
239 final ProfileDefaultHandler handler= new ProfileDefaultHandler();
241 final SAXParserFactory factory= SAXParserFactory.newInstance();
242 final SAXParser parser= factory.newSAXParser();
243 parser.parse(inputSource, handler);
244 } catch (SAXException e) {
245 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_reading_xml_message);
246 } catch (IOException e) {
247 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_reading_xml_message);
248 } catch (ParserConfigurationException e) {
249 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_reading_xml_message);
251 return handler.getProfiles();
255 * Write the available profiles to the internal XML file.
256 * @param profiles List of <code>CustomProfile</code>
257 * @param file File to write
258 * @param encoding the encoding to use
259 * @throws CoreException
261 public void writeProfilesToFile(Collection<Profile> profiles, File file, String encoding) throws CoreException {
262 final OutputStream stream;
264 stream= new FileOutputStream(file);
266 writeProfilesToStream(profiles, stream, encoding, fProfileVersioner);
268 try { stream.close(); } catch (IOException e) { /* ignore */ }
270 } catch (IOException e) {
271 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_serializing_xml_message);
275 public List<Profile> generated_6519699636150707677(ProfileConfigurationBlock profileconfigurationblock, List<Profile> profiles) {
277 profiles= readProfiles(profileconfigurationblock.fInstanceScope);
278 } catch (CoreException e) {
281 if (profiles == null) {
284 profiles= readProfiles(DefaultScope.INSTANCE);
285 } catch (CoreException e) {
290 if (profiles == null)
291 profiles= new ArrayList<Profile>();
296 * Save profiles to an XML stream
297 * @param profiles the list of <code>CustomProfile</code>
298 * @param stream the stream to write to
299 * @param encoding the encoding to use
300 * @throws CoreException
302 public static void writeProfilesToStream(Collection<Profile> profiles, OutputStream stream, String encoding, IProfileVersioner profileVersioner) throws CoreException {
305 final DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
306 final DocumentBuilder builder= factory.newDocumentBuilder();
307 final Document document= builder.newDocument();
309 final Element rootElement = document.createElement(XML_NODE_ROOT);
310 rootElement.setAttribute(XML_ATTRIBUTE_VERSION, Integer.toString(profileVersioner.getCurrentVersion()));
312 document.appendChild(rootElement);
314 for(final Iterator<Profile> iter= profiles.iterator(); iter.hasNext();) {
315 final Profile profile= iter.next();
316 if (profile.isProfileToSave()) {
317 final Element profileElement= createProfileElement(profile, document, profileVersioner);
318 rootElement.appendChild(profileElement);
322 Transformer transformer=TransformerFactory.newInstance().newTransformer();
323 transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
324 transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
325 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
326 transformer.transform(new DOMSource(document), new StreamResult(stream));
327 } catch (TransformerException e) {
328 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_serializing_xml_message);
329 } catch (ParserConfigurationException e) {
330 throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_serializing_xml_message);
336 * Create a new profile element in the specified document. The profile is not added
337 * to the document by this method.
339 private static Element createProfileElement(Profile profile, Document document, IProfileVersioner profileVersioner) {
340 final Element element= document.createElement(XML_NODE_PROFILE);
341 element.setAttribute(XML_ATTRIBUTE_NAME, profile.getName());
342 element.setAttribute(XML_ATTRIBUTE_VERSION, Integer.toString(profile.getVersion()));
343 element.setAttribute(XML_ATTRIBUTE_PROFILE_KIND, profileVersioner.getProfileKind());
345 final Iterator<String> keyIter= profile.getSettings().keySet().iterator();
347 while (keyIter.hasNext()) {
348 final String key= keyIter.next();
349 final String value= profile.getSettings().get(key);
351 final Element setting= document.createElement(XML_NODE_SETTING);
352 setting.setAttribute(XML_ATTRIBUTE_ID, key);
353 setting.setAttribute(XML_ATTRIBUTE_VALUE, value);
354 element.appendChild(setting);
356 JavaPlugin.logErrorMessage("ProfileStore: Profile does not contain value for key " + key); //$NON-NLS-1$
364 * Creates a UI exception for logging purposes
366 private static JavaUIException createException(Throwable t, String message) {
367 return new JavaUIException(JavaUIStatus.createError(IStatus.ERROR, message, t));