/******************************************************************************* * Copyright (c) 2015-2016 Open Analytics NV and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.linuxtools.internal.docker.editor; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnmappableCharacterException; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.rules.FastPartitioner; import org.eclipse.linuxtools.internal.docker.editor.scanner.DockerPartitionScanner; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.editors.text.FileDocumentProvider; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel; public class DockerDocumentProvider extends FileDocumentProvider { @Override protected IDocument createDocument(Object element) throws CoreException { IDocument document = super.createDocument(element); if (document != null) { DockerPartitionScanner scanner = new DockerPartitionScanner(); IDocumentPartitioner partitioner = new FastPartitioner(scanner, DockerPartitionScanner.ALLOWED_CONTENT_TYPES); partitioner.connect(document); document.setDocumentPartitioner(partitioner); } return document; } @Override public String getEncoding(Object element) { return Charset.defaultCharset().name(); } @Override public boolean isReadOnly(Object element) { if (element instanceof FileStoreEditorInput) { String path = ((FileStoreEditorInput) element).getURI().getPath(); return !new File(path).canWrite(); } else { return super.isReadOnly(element); } } @Override public boolean isModifiable(Object element) { if (element instanceof FileStoreEditorInput) { String path = ((FileStoreEditorInput) element).getURI().getPath(); return new File(path).canWrite(); } else { return super.isModifiable(element); } } @Override protected boolean setDocumentContent(IDocument document, IEditorInput editorInput, String encoding) throws CoreException { if (editorInput instanceof FileStoreEditorInput) { String path = ((FileStoreEditorInput) editorInput).getURI().getPath(); InputStream in; try { in = new FileInputStream(path); } catch (FileNotFoundException e) { return false; } super.setDocumentContent(document, in, encoding); return true; } else { return super.setDocumentContent(document, editorInput, encoding); } } @Override protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException { if (element instanceof FileStoreEditorInput) { String encoding = null; ElementInfo info = getElementInfo(element); Path filePath = Paths.get(((FileStoreEditorInput) element).getURI().getPath()); encoding = getEncoding(element); Charset charset; try { charset = Charset.forName(encoding); } catch (UnsupportedCharsetException ex) { String message = NLS.bind(Messages.DockerDocumentProvider_encoding_not_supported, encoding); IStatus s = new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, message, ex); throw new CoreException(s); } catch (IllegalCharsetNameException ex) { String message = NLS.bind(Messages.DockerDocumentProvider_encoding_not_legal, encoding); IStatus s = new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, message, ex); throw new CoreException(s); } CharsetEncoder encoder = charset.newEncoder(); encoder.onMalformedInput(CodingErrorAction.REPLACE); encoder.onUnmappableCharacter(CodingErrorAction.REPORT); InputStream stream; try { byte[] bytes; ByteBuffer byteBuffer = encoder.encode(CharBuffer.wrap(document.get())); if (byteBuffer.hasArray()) bytes = byteBuffer.array(); else { bytes = new byte[byteBuffer.limit()]; byteBuffer.get(bytes); } stream = new ByteArrayInputStream(bytes, 0, byteBuffer.limit()); } catch (CharacterCodingException ex) { Assert.isTrue(ex instanceof UnmappableCharacterException); String message = NLS.bind( Messages.DockerDocumentProvider_cannot_be_mapped + Messages.DockerDocumentProvider_chars_not_supported, encoding); IStatus s = new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, EditorsUI.CHARSET_MAPPING_FAILED, message, null); throw new CoreException(s); } if (Files.exists(filePath)) { // inform about the upcoming content change fireElementStateChanging(element); try (FileWriter fw = new FileWriter(filePath.toFile()); InputStreamReader istream = new InputStreamReader(stream)) { char[] bb = new char[1024]; int nRead = istream.read(bb); while (nRead > 0) { fw.write(bb, 0, nRead); nRead = istream.read(bb); } } catch (RuntimeException | IOException x) { // inform about failure fireElementStateChangeFailed(element); throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, x.getMessage())); } // If here, the editor state will be flipped to "not dirty". // Thus, the state changing flag will be reset. if (info != null) { ResourceMarkerAnnotationModel model = (ResourceMarkerAnnotationModel) info.fModel; if (model != null) model.updateMarkers(info.fDocument); } } else { try { Files.createFile(filePath); try (FileWriter fw = new FileWriter(filePath.toFile()); InputStreamReader istream = new InputStreamReader(stream)) { char[] bb = new char[1024]; int nRead = istream.read(bb); while (nRead > 0) { fw.write(bb, 0, nRead); nRead = istream.read(bb); } } catch (IOException x) { throw x; } } catch (IOException e) { throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage())); } finally { monitor.done(); } } } else { super.doSaveDocument(monitor, element, document, overwrite); } } }