| /********************************************************************* |
| * Copyright (c) 2009 - 2012 SpringSource, a division of VMware, Inc. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| **********************************************************************/ |
| |
| package org.eclipse.virgo.ide.manifest.internal.core.model; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.nio.ByteBuffer; |
| import java.nio.charset.Charset; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.virgo.ide.manifest.core.BundleManifestCoreMessages; |
| |
| /** |
| * @author Christian Dupuis |
| * @since 1.0.0 |
| */ |
| /** |
| * TODO CD add comments |
| */ |
| public class BundleManifest extends AbstractManifestElement { |
| |
| private static final int BUNDLE_MANIFEST_TYPE = 1; |
| |
| private final IFile file; |
| |
| private Map<String, BundleManifestHeader> headerMap; |
| |
| // private Set<ValidationProblem> problems; |
| |
| private IDocument textDocument; |
| |
| public BundleManifest(IFile file) { |
| super(null, file.getName()); |
| this.file = file; |
| // this.problems = new LinkedHashSet<ValidationProblem>(); |
| init(); |
| } |
| |
| public IDocument getDocument() { |
| return this.textDocument; |
| } |
| |
| @Override |
| public AbstractManifestElement[] getChildren() { |
| List<BundleManifestHeader> headers = new ArrayList<BundleManifestHeader>(this.headerMap.values()); |
| Collections.sort(headers, new Comparator<BundleManifestHeader>() { |
| |
| public int compare(BundleManifestHeader o1, BundleManifestHeader o2) { |
| return new Integer(o1.getLineNumber()).compareTo(new Integer(o2.getLineNumber())); |
| } |
| }); |
| |
| return headers.toArray(new BundleManifestHeader[this.headerMap.size()]); |
| } |
| |
| public IResource getElementResource() { |
| return this.file; |
| } |
| |
| public int getElementType() { |
| return BUNDLE_MANIFEST_TYPE; |
| } |
| |
| public BundleManifestHeader getHeader(String key) { |
| return this.headerMap.get(key.toLowerCase()); |
| } |
| |
| // public Set<ValidationProblem> getProblems() { |
| // return problems; |
| // } |
| |
| public boolean isElementArchived() { |
| return false; |
| } |
| |
| public boolean isExternal() { |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| builder.append(this.file.getLocation().toString()).append("\n"); |
| for (AbstractManifestElement element : getChildren()) { |
| builder.append(element.toString()).append("\n"); |
| } |
| return builder.toString(); |
| } |
| |
| private String getHeaderName(String line) { |
| for (int i = 0; i < line.length(); i++) { |
| char c = line.charAt(i); |
| if (c == ':') { |
| return line.substring(0, i); |
| } |
| if ((c < 'A' || 'Z' < c) && (c < 'a' || 'z' < c) && (c < '0' || '9' < c)) { |
| if (i == 0) { |
| return null; |
| } |
| if (c != '-' && c != '_') { |
| return null; |
| } |
| } |
| } |
| return null; |
| } |
| |
| protected IDocument createDocument(IFile file) { |
| if (!file.exists()) { |
| return null; |
| } |
| try { |
| // brute force here as we need to get the final file contents as it might have been |
| // updated by bundlor |
| String contents = convertStreamToString(file.getContents(true)); |
| return new Document(contents); |
| } catch (CoreException e) { |
| } |
| return null; |
| } |
| |
| protected void error(int severity, String message, int line) { |
| // TODO: re-implement validation with Eclipse APIs |
| // problems.add(new ValidationProblem(severity, message, file, line)); |
| } |
| |
| protected void init() { |
| this.textDocument = createDocument(this.file); |
| parseManifest(this.textDocument); |
| } |
| |
| protected void parseManifest(IDocument document) { |
| try { |
| this.headerMap = new HashMap<String, BundleManifestHeader>(); |
| BundleManifestHeader header = null; |
| int l = 0; |
| for (; l < document.getNumberOfLines(); l++) { |
| IRegion lineInfo = document.getLineInformation(l); |
| String line = document.get(lineInfo.getOffset(), lineInfo.getLength()); |
| // test lines' length |
| Charset charset = Charset.forName("UTF-8"); //$NON-NLS-1$ |
| String lineDelimiter = document.getLineDelimiter(l); |
| if (lineDelimiter == null) { |
| lineDelimiter = ""; //$NON-NLS-1$ |
| } |
| ByteBuffer byteBuf = charset.encode(line); |
| if (byteBuf.limit() + lineDelimiter.length() > 512) { |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_lineTooLong, l + 1); |
| return; |
| } |
| // parse |
| if (line.length() == 0) { |
| // Empty Line |
| if (l == 0) { |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_noMainSection, 1); |
| return; |
| } |
| /* flush last line */ |
| if (header != null) { |
| this.headerMap.put(header.getName().toLowerCase(), header); |
| header = null; |
| } |
| break; /* done processing main attributes */ |
| } |
| if (line.charAt(0) == ' ') { |
| // Continuation Line |
| if (l == 0) { /* if no previous line */ |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_noMainSection, 1); |
| return; |
| } |
| if (header != null) { |
| header.append(line.substring(1)); |
| } |
| |
| continue; |
| } |
| // Expecting New Header |
| if (header != null) { |
| this.headerMap.put(header.getName().toLowerCase(), header); |
| header = null; |
| } |
| |
| int colon = line.indexOf(':'); |
| if (colon == -1) { /* no colon */ |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_noColon, l + 1); |
| return; |
| } |
| String headerName = getHeaderName(line); |
| if (headerName == null) { |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_invalidHeaderName, l + 1); |
| return; |
| } |
| if (line.length() < colon + 2 || line.charAt(colon + 1) != ' ') { |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_noSpaceValue, l + 1); |
| return; |
| } |
| if ("Name".equals(headerName)) { //$NON-NLS-1$ |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_nameHeaderInMain, l + 1); |
| return; |
| } |
| header = new BundleManifestHeader(this, headerName, line.substring(colon + 2), l); |
| if (this.headerMap.containsKey(header.getName().toLowerCase())) { |
| error(IMarker.SEVERITY_WARNING, BundleManifestCoreMessages.BundleErrorReporter_duplicateHeader, l + 1); |
| } |
| |
| } |
| if (header != null) { |
| // lingering header, line not terminated |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_noLineTermination, l + 1); |
| return; |
| } |
| // If there is any more headers, not starting with a Name header |
| // the empty lines are a mistake, report it. |
| for (; l < document.getNumberOfLines(); l++) { |
| IRegion lineInfo = document.getLineInformation(l); |
| String line = document.get(lineInfo.getOffset(), lineInfo.getLength()); |
| if (line.length() == 0) { |
| continue; |
| } |
| if (!line.startsWith("Name:")) { //$NON-NLS-1$ |
| error(IMarker.SEVERITY_ERROR, BundleManifestCoreMessages.BundleErrorReporter_noNameHeader, l); |
| } |
| break; |
| } |
| |
| } catch (BadLocationException ble) { |
| } |
| } |
| |
| public String convertStreamToString(InputStream is) { |
| BufferedReader reader = new BufferedReader(new InputStreamReader(is)); |
| StringBuilder sb = new StringBuilder(); |
| |
| String line = null; |
| try { |
| while ((line = reader.readLine()) != null) { |
| sb.append(line + "\n"); |
| } |
| } catch (IOException e) { |
| } finally { |
| try { |
| is.close(); |
| } catch (IOException e) { |
| } |
| } |
| |
| return sb.toString(); |
| } |
| } |