blob: 1acd24af84fcef3d7c1886d358bd814ae68f8128 [file] [log] [blame]
/*********************************************************************
* 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();
}
}