/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.karaf.shell.commands;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;
import java.util.regex.Pattern;
import jline.Terminal;
import org.apache.felix.gogo.commands.Argument;
import org.apache.felix.gogo.commands.Command;
import org.apache.karaf.shell.console.AbstractAction;
import org.jledit.ConsoleEditor;
import org.jledit.EditorFactory;
@Command(scope = "shell", name = "edit", description = "Calls a text editor.")
public class EditAction extends AbstractAction {
private final Pattern URL_PATTERN = Pattern.compile("[^: ]+:[^ ]+");
@Argument(index = 0, name = "url", description = "The url of the resource to edit.", required = true, multiValued = false)
private String url;
private EditorFactory editorFactory;
@Override
protected Object doExecute() throws Exception {
URLConnection connection = null;
InputStream is = null;
OutputStream os = null;
String path = null;
boolean isLocal = true;
String sourceUrl = url;
// if no url format found, assume file url
if (!URL_PATTERN.matcher(sourceUrl).matches()) {
File f = new File(sourceUrl);
sourceUrl = "file://" + f.getAbsolutePath();
}
URL u = new URL(sourceUrl);
// if its not a file url
if (!u.getProtocol().equals("file")) {
isLocal = false;
try {
connection = u.openConnection();
is = connection.getInputStream();
} catch (IOException ex) {
System.out.println("Failed to open " + sourceUrl + " for reading.");
return null;
}
try {
os = connection.getOutputStream();
} catch (IOException ex) {
System.out.println("Failed to open " + sourceUrl + " for writing.");
return null;
}
// copy the resource to a tmp location
FileOutputStream fos = null;
try {
path = System.getProperty("karaf.data") + "/editor/" + UUID.randomUUID();
File f = new File(path);
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
}
fos = new FileOutputStream(f);
copy(is, fos);
} catch (Exception ex) {
System.out.println("Failed to copy resource from url:" + sourceUrl + " to tmp file: " + path + " for editing.");
} finally {
close(fos);
}
} else {
path = u.getFile();
}
File file = new File(path);
if (!file.exists()) {
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
}
// call the editor
ConsoleEditor editor = editorFactory.create(getTerminal());
editor.setTitle("Karaf");
editor.open(file.getAbsolutePath(), url);
editor.setOpenEnabled(false);
editor.start();
// if resource is not local, copy the resource back
if (!isLocal) {
FileInputStream fis = new FileInputStream(path);
try {
copy(fis, os);
} finally {
close(fis);
}
}
if (is != null) {
close(is);
}
if (os != null) {
close(os);
}
return null;
}
/**
* Gets the {@link jline.Terminal} from the current session.
*
* @return
* @throws Exception
*/
private Terminal getTerminal() throws Exception {
Object terminalObject = session.get(".jline.terminal");
if (terminalObject instanceof Terminal) {
return (Terminal) terminalObject;
}
throw new IllegalStateException("Could not get Terminal from CommandSession.");
}
/**
* Copies the content of {@link InputStream} to {@link OutputStream}.
*
* @param input
* @param output
* @throws IOException
*/
private void copy(final InputStream input, final OutputStream output) throws IOException {
byte[] buffer = new byte[1024 * 16];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
output.flush();
}
}
public EditorFactory getEditorFactory() {
return editorFactory;
}
public void setEditorFactory(EditorFactory editorFactory) {
this.editorFactory = editorFactory;
}
private static void close(Closeable... closeables) {
for (Closeable c : closeables) {
try {
if (c != null) {
c.close();
}
} catch (IOException e) {
// Ignore
}
}
}
}