blob: 25a7febca7347dafd85060e42dab0a9a541c2637 [file] [log] [blame]
/*
* Copyright (c) 2014, 2015 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.preferences.impl;
import org.eclipse.oomph.preferences.PreferenceNode;
import org.eclipse.oomph.preferences.PreferencesPackage;
import org.eclipse.oomph.preferences.Property;
import org.eclipse.oomph.preferences.util.PreferencesUtil;
import org.eclipse.oomph.util.IOExceptionWithCause;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.URIHandlerImpl;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.equinox.security.storage.StorageException;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/**
* @author Ed Merks
*/
public class PreferencesURIHandlerImpl extends URIHandlerImpl
{
private static final IEclipsePreferences ROOT = Platform.getPreferencesService().getRootNode();
@Override
public boolean canHandle(URI uri)
{
return "preference".equals(uri.scheme());
}
protected static class PreferenceAccessor
{
private final Preferences preferences;
private final ISecurePreferences securePreferences;
private final String key;
private final boolean isEncrypted;
public PreferenceAccessor(URI uri)
{
String[] segments = uri.segments();
int last = segments.length - 1;
if ("secure".equals(segments[0]))
{
ISecurePreferences node = PreferencesUtil.getSecurePreferences();
for (int i = 1; i < last; ++i)
{
node = node.node(segments[i]);
}
preferences = null;
securePreferences = node;
isEncrypted = !"encrypted=false".equals(uri.query());
}
else
{
Preferences node = ROOT;
for (int i = 0; i < last; ++i)
{
node = node.node(segments[i]);
}
preferences = node;
securePreferences = null;
isEncrypted = false;
}
key = segments[last];
}
public String get() throws IOException
{
try
{
return securePreferences == null ? preferences.get(key, null) : securePreferences.get(key, null);
}
catch (StorageException ex)
{
throw new IOExceptionWithCause(ex);
}
}
public void put(String value) throws IOException
{
if (securePreferences == null)
{
preferences.put(key, value);
}
else
{
try
{
boolean encrypt = isEncrypted;
for (String key : securePreferences.keys())
{
if (key.equals(this.key))
{
encrypt = securePreferences.isEncrypted(key);
break;
}
}
securePreferences.put(key, value, encrypt);
}
catch (StorageException ex)
{
throw new IOExceptionWithCause(ex);
}
}
flush();
}
public void remove() throws IOException
{
if (securePreferences == null)
{
preferences.remove(key);
}
else
{
securePreferences.remove(key);
}
flush();
}
private void flush() throws IOException
{
try
{
if (securePreferences == null)
{
preferences.flush();
}
else
{
securePreferences.flush();
}
}
catch (BackingStoreException ex)
{
throw new IOExceptionWithCause(ex);
}
}
}
@Override
public InputStream createInputStream(URI uri, final Map<?, ?> options) throws IOException
{
if (uri.segmentCount() == 1)
{
class PreferencesInput extends InputStream implements URIConverter.Loadable
{
private PreferenceNode preferencesNode = PreferencesUtil
.getRootPreferenceNode(Boolean.TRUE.equals(options.get(PreferencesUtil.OPTION_SYNCHRONIZED_PREFERENCES)));
private InputStream in;
public void loadResource(Resource resource) throws IOException
{
resource.getContents().add(preferencesNode);
}
@Override
public int read() throws IOException
{
if (in == null)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
preferencesNode.eResource().save(out, null);
in = new ByteArrayInputStream(out.toByteArray());
}
return in.read();
}
}
return new PreferencesInput();
}
URI preferencePath = uri.trimSegments(1);
String value = new PreferenceAccessor(preferencePath).get();
if (value == null)
{
throw new IOException("No preference value available for " + preferencePath);
}
return new URIConverter.ReadableInputStream(value);
}
@Override
public OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException
{
if (uri.segmentCount() == 1)
{
class PreferencesOutput extends OutputStream implements URIConverter.Saveable
{
public void saveResource(Resource resource) throws IOException
{
Copier copier = new Copier()
{
private static final long serialVersionUID = 1L;
@Override
protected void copyAttribute(EAttribute eAttribute, EObject eObject, EObject copyEObject)
{
if (eAttribute == PreferencesPackage.Literals.PROPERTY__VALUE)
{
Property property = (Property)eObject;
Property copyProperty = (Property)copyEObject;
copyProperty.setValue(property.getSecureValue());
}
else
{
super.copyAttribute(eAttribute, eObject, copyEObject);
}
}
};
PreferenceNode root = (PreferenceNode)copier.copy(resource.getContents().get(0));
copier.copyReferences();
Throwable throwable = null;
try
{
Collection<? extends IEclipsePreferences> flush = PreferencesUtil.reconcile(root);
for (IEclipsePreferences preferences : flush)
{
try
{
preferences.flush();
}
catch (Throwable ex)
{
throwable = ex;
}
}
}
catch (Throwable ex)
{
IOException ioException = new IOException(ex.getMessage());
ioException.initCause(ex);
throw ioException;
}
if (throwable != null)
{
IOException ioException = new IOException(throwable.getMessage());
ioException.initCause(throwable);
throw ioException;
}
}
@Override
public void write(int b) throws IOException
{
throw new IOException("Streamed output not supported");
}
}
return new PreferencesOutput();
}
final PreferenceAccessor accessor = new PreferenceAccessor(uri.trimSegments(1));
return new URIConverter.WriteableOutputStream(new StringWriter()
{
@Override
public void close() throws IOException
{
super.close();
accessor.put(toString());
}
}, "UTF-8");
}
@Override
public void delete(URI uri, Map<?, ?> options) throws IOException
{
new PreferenceAccessor(uri.trimSegments(1)).remove();
}
@Override
public boolean exists(URI uri, Map<?, ?> options)
{
try
{
return new PreferenceAccessor(uri.trimSegments(1)).get() != null;
}
catch (IOException ex)
{
return false;
}
}
@Override
public Map<String, ?> getAttributes(URI uri, Map<?, ?> options)
{
return Collections.emptyMap();
}
@Override
public void setAttributes(URI uri, Map<String, ?> attributes, Map<?, ?> options) throws IOException
{
// Do nothing.
}
}