Commit 26401e3a authored by Marco Descher's avatar Marco Descher 🏔

Add p2 update feature, multiple changes

parent 899d8f43
......@@ -3,10 +3,6 @@
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.ear
rebel.xml
bin/
target/
......@@ -16,3 +12,9 @@ profile.tmp
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
## OS
.DS_Store
Icon?
nohup.out
.bak
......@@ -6,6 +6,8 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Activator: info.elexis.server.core.p2.Activator
Bundle-Vendor: elexis.info
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.equinox.ds,
org.eclipse.osgi.services,
org.eclipse.equinox.security,
org.eclipse.equinox.p2.core,
org.eclipse.equinox.p2.engine,
......@@ -19,11 +21,15 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.ecf.identity;bundle-version="3.1.200",
org.eclipse.ecf.provider.filetransfer;bundle-version="3.2.0",
org.eclipse.ecf.provider.filetransfer.httpclient4;bundle-version="1.0.2000",
org.eclipse.core.net;bundle-version="1.2.300",
info.elexis.server.core;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Service-Component: OSGI-INF/*.xml
Import-Package: javax.ws.rs;version="1.1.1",
Import-Package: javax.servlet;version="3.1.0",
javax.servlet.http;version="2.4.0",
javax.ws.rs;version="1.1.1",
javax.ws.rs.core;version="2.0.1",
org.osgi.service.component.annotations;version="1.2.0",
org.slf4j
Export-Package: info.elexis.server.core.p2
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="info.elexis.server.core.p2.internal.Provisioner" activate="activate">
<implementation class="info.elexis.server.core.p2.internal.Provisioner"/>
<reference name="AgentProvider" interface="org.eclipse.equinox.p2.core.IProvisioningAgentProvider" cardinality="1..1" policy="static" bind="setAgentProvider" unbind="unsetAgentProvider"/>
</scr:component>
org.eclipse.equinox.p2.core.ProvisionException: Error while reading from repository ->
https://wiki.eclipse.org/Disabling_Apache_Httpclient
http://stackoverflow.com/questions/22148782/unable-to-connect-to-the-eclipse-luna-market
\ No newline at end of file
package info.elexis.server.core.p2;
import java.util.Collection;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.p2.operations.Update;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.elexis.server.core.p2.internal.Provisioner;
import info.elexis.server.core.p2.internal.ProvisioningHelper;
import it.sauronsoftware.cron4j.Task;
import it.sauronsoftware.cron4j.TaskExecutionContext;
public class SystemUpdateTask extends Task {
private Logger log = LoggerFactory.getLogger(SystemUpdateTask.class);
@Override
public void execute(TaskExecutionContext context) throws RuntimeException {
Provisioner p = new Provisioner();
if(!p.updateServiceIsConnectable()) {
log.warn("Update service is not connectable.");
context.setStatusMessage("Update service is not connectable.");
return;
}
Collection<Update> availableUpdates = p.getAvailableUpdates();
if(availableUpdates.size()>0) {
p.update(availableUpdates, new NullProgressMonitor());
}
context.setStatusMessage("Checking for updates");
IStatus updateAllFeatures = ProvisioningHelper.updateAllFeatures();
context.setStatusMessage(updateAllFeatures.getMessage());
}
@Override
......
package info.elexis.server.core.p2.internal;
/**
* This class can be used for simple benchmarks.
*/
public class BenchmarkTimer {
private long startTime = 0;
private long endTime = 0;
public void start(){
this.startTime = System.currentTimeMillis();
}
public void end(){
this.endTime = System.currentTimeMillis();
}
public long getStartTime(){
return this.startTime;
}
public long getEndTime(){
return this.endTime;
}
public long getTotalTime(){
return this.endTime - this.startTime;
}
public String geTotalTimeHumanReadableString(){
return convertMS(getTotalTime());
}
private String convertMS(long ms){
int seconds = (int) ((ms / 1000) % 60);
int minutes = (int) (((ms / 1000) / 60) % 60);
int hours = (int) ((((ms / 1000) / 60) / 60) % 24);
String sec, min, hrs;
if (seconds < 10)
sec = "0" + seconds;
else
sec = "" + seconds;
if (minutes < 10)
min = "0" + minutes;
else
min = "" + minutes;
if (hours < 10)
hrs = "0" + hours;
else
hrs = "" + hours;
if (hours == 0)
return min + " min, " + sec + " sec";
else
return hrs + " hrs, " + min + "min, " + sec + " sec";
}
}
package info.elexis.server.core.p2.internal;
public class Constants {
public static final String MAIN_DOWNLOAD_URL = "https://download.elexis.info/elexis-server/";
public static final String PROVISIONING_UPDATE_REPO = null;
}
package info.elexis.server.core.p2.internal;
import java.util.Optional;
import javax.annotation.security.RolesAllowed;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response;
import org.osgi.service.component.annotations.Component;
@Component(service = HTTPService.class, immediate = true)
@Path("/p2")
@RolesAllowed("admin")
public class HTTPService {
@Context
UriInfo uriInfo;
@Context
Request request;
private HttpServletRequest req;
@GET
@Path("/repositories")
public Response listRepositories(@QueryParam("filter") String filter) {
return HTTPServiceHelper.doRepositoryList(filter);
}
@GET
@Path("/repositories/add")
public Response addRepository(@QueryParam("location") String location) {
Optional<String> locStr = Optional.ofNullable(location);
if (locStr.isPresent()) {
return HTTPServiceHelper.doRepositoryAdd(locStr.get());
}
return Response.status(Response.Status.BAD_REQUEST).build();
}
@GET
@Path("/repositories/remove")
public Response handleRemove(@QueryParam("location") String location) {
Optional<String> locStr = Optional.ofNullable(location);
if (locStr.isPresent()) {
return HTTPServiceHelper.doRepositoryRemove(locStr.get());
}
return Response.status(Response.Status.BAD_REQUEST).build();
}
@GET
@Path("/update")
public Response performUpdate() {
return HTTPServiceHelper.doUpdateAllFeatures();
}
}
package info.elexis.server.core.p2.internal;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import javax.ws.rs.core.Response;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HTTPServiceHelper {
private static Logger log = LoggerFactory.getLogger(HTTPServiceHelper.class);
public static Response doRepositoryList(String filterStr) {
int filter = IRepositoryManager.REPOSITORIES_ALL;
try {
if (filterStr != null) {
filter = Integer.parseInt(filterStr);
}
} catch (NumberFormatException localException) {
log.error("NaN " + filterStr, localException);
return Response.status(Response.Status.BAD_REQUEST).build();
}
RepoInfo info = new RepoInfo();
IMetadataRepositoryManager metadataRepoMgr = Provisioner.getInstance().getMetadataRepositoryManager();
IMetadataRepository repo;
for (URI repoLoc : metadataRepoMgr.getKnownRepositories(filter)) {
String repoName;
try {
repo = metadataRepoMgr.loadRepository(repoLoc, new TimeoutProgressMonitor(2000));
repoName = repo.getName();
} catch (OperationCanceledException localOperationCanceledException) {
log.warn("timeout", localOperationCanceledException);
repoName = "timeout";
} catch (ProvisionException localProvisionException) {
log.error("FAIL", localProvisionException);
repoName = "FAILED: " + localProvisionException.getLocalizedMessage();
}
info.addMetadataRepoElement(repoName, repoLoc);
}
IArtifactRepositoryManager articaftRepoMgr = Provisioner.getInstance().getArtifactRepositoryManager();
IArtifactRepository artRepo;
for (URI repoLoc : articaftRepoMgr.getKnownRepositories(filter)) {
String repoName;
try {
artRepo = articaftRepoMgr.loadRepository(repoLoc, new TimeoutProgressMonitor(2000));
repoName = artRepo.getName();
} catch (OperationCanceledException localOperationCanceledException) {
log.warn("timeout", localOperationCanceledException);
repoName = "timeout";
} catch (ProvisionException localProvisionException) {
log.error("FAIL", localProvisionException);
repoName = "FAILED: " + localProvisionException.getLocalizedMessage();
}
info.addArtifactRepoElement(repoName, repoLoc);
}
return Response.ok(info).build();
}
public static Response doRepositoryAdd(String locStr) {
URI location = null;
try {
locStr = URLDecoder.decode(locStr, "ASCII");
location = new URI(locStr);
} catch (URISyntaxException | UnsupportedEncodingException e) {
log.error("Exception parsing URI " + locStr, e);
return Response.status(Response.Status.BAD_REQUEST).build();
}
if (location.isAbsolute()) {
ProvisioningHelper.addRepository(location);
return Response.ok().build();
}
log.warn("Tried to add non absolute location: {}", location);
return Response.status(Response.Status.BAD_REQUEST).build();
}
public static Response doRepositoryRemove(String locStr) {
URI location = null;
try {
locStr = URLDecoder.decode(locStr, "ASCII");
location = new URI(locStr);
} catch (URISyntaxException | UnsupportedEncodingException e) {
log.error("Exception parsing URI " + locStr, e);
return Response.status(Response.Status.BAD_REQUEST).build();
}
boolean result = ProvisioningHelper.removeRepository(location);
if (result) {
return Response.ok().build();
}
return Response.serverError().build();
}
public static Response doUpdateAllFeatures() {
IStatus updateStatus = ProvisioningHelper.updateAllFeatures();
return createResponseFromStatus("doUpdateAllFeatures", updateStatus);
}
private static Response createResponseFromStatus(String op, IStatus stat) {
if (stat.isOK()) {
return Response.ok().build();
}
log.error("Error performing operation [{}] : Code {} / {}", op, stat.getCode(), stat.getMessage());
return Response.serverError().build();
}
}
package info.elexis.server.core.p2.internal;
import java.net.URI;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.operations.ProfileChangeOperation;
import org.eclipse.equinox.p2.operations.ProvisioningJob;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
import org.eclipse.equinox.p2.operations.UpdateOperation;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProvisioningHelper {
private static Logger log = LoggerFactory.getLogger(ProvisioningHelper.class);
static void refreshRepositories() {
IMetadataRepositoryManager metadataRepoMgr = Provisioner.getInstance().getMetadataRepositoryManager();
for (URI repo : metadataRepoMgr.getKnownRepositories(0)) {
try {
metadataRepoMgr.refreshRepository(repo, new NullProgressMonitor());
} catch (ProvisionException | OperationCanceledException e) {
log.error("Exception refreshing repo " + repo, e);
}
}
IArtifactRepositoryManager artifactRepoMgr = Provisioner.getInstance().getArtifactRepositoryManager();
for (URI repo : artifactRepoMgr.getKnownRepositories(0))
try {
artifactRepoMgr.refreshRepository(repo, new NullProgressMonitor());
} catch (ProvisionException | OperationCanceledException e) {
log.error("Exception refreshing repo " + repo, e);
}
}
static IStatus performOperation(ProfileChangeOperation op) {
ProvisioningJob job = op.getProvisioningJob(new NullProgressMonitor());
return job.runModal(new NullProgressMonitor());
}
/**
*
* @param location
* @return <code>true</code> if repository was removed or it was already not
* part of the list
*/
public static boolean removeRepository(URI location) {
boolean result = true;
IArtifactRepositoryManager artifactRepoMgr = Provisioner.getInstance().getArtifactRepositoryManager();
if (artifactRepoMgr.contains(location)) {
result &= artifactRepoMgr.removeRepository(location);
log.debug("Removed artifact repository " + location);
}
IMetadataRepositoryManager metadataRepoMgr = Provisioner.getInstance().getMetadataRepositoryManager();
if (metadataRepoMgr.contains(location)) {
result &= metadataRepoMgr.removeRepository(location);
log.debug("Removed metadata repository " + location);
}
return result;
}
public static void addRepository(URI location) {
IArtifactRepositoryManager artifactRepoMgr = Provisioner.getInstance().getArtifactRepositoryManager();
if (!artifactRepoMgr.contains(location)) {
artifactRepoMgr.addRepository(location);
log.debug("Added artifact repository " + location);
}
IMetadataRepositoryManager metadataRepoMgr = Provisioner.getInstance().getMetadataRepositoryManager();
if (!metadataRepoMgr.contains(location)) {
metadataRepoMgr.addRepository(location);
log.debug("Added artifact repository " + location);
}
}
public static IStatus updateAllFeatures() {
IProvisioningAgent agent = Provisioner.getInstance().getProvisioningAgent();
ProvisioningHelper.refreshRepositories();
IProfileRegistry registry = Provisioner.getInstance().getProfileRegistry();
IProfile profile = registry.getProfile(Provisioner.getInstance().getCurrentProfile());
ProvisioningSession session = new ProvisioningSession(agent);
IQuery<IInstallableUnit> query = QueryUtil.createIUAnyQuery();
IQueryResult<IInstallableUnit> units = profile.query(query, new NullProgressMonitor());
UpdateOperation operation = new UpdateOperation(session, units.toUnmodifiableSet());
operation.setProfileId(Provisioner.getInstance().getCurrentProfile());
IStatus status = operation.resolveModal(new TimeoutProgressMonitor(5000));
log.debug("CHECK_FOR_UPDATE {} | severity {} | code {}", status.getMessage(), status.getSeverity(),
status.getCode());
if (status.getSeverity() != IStatus.ERROR) {
IStatus stat = ProvisioningHelper.performOperation(operation);
log.info("UPDATED {} / {}", stat.getCode(), stat.getMessage());
}
return status;
}
}
package info.elexis.server.core.p2.internal;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class RepoInfo {
@XmlElement
public List<RepoElement> metadataRepos = new ArrayList<RepoInfo.RepoElement>();
@XmlElement
public List<RepoElement> artifactRepos = new ArrayList<RepoInfo.RepoElement>();
public void addMetadataRepoElement(String repoName, URI repoLoc) {
metadataRepos.add(new RepoElement(repoName, repoLoc));
}
public void addArtifactRepoElement(String repoName, URI repoLoc) {
artifactRepos.add(new RepoElement(repoName, repoLoc));
}
public static class RepoElement {
private String name;
private URI uri;
public RepoElement(String repoName, URI repoLoc) {
name = repoName;
uri = repoLoc;
}
public String getName() {
return this.name;
}
public URI getURI() {
return this.uri;
}
public void setName(String name) {
this.name = name;
}
public void setURI(URI uri) {
this.uri = uri;
}
}
}
/*******************************************************************************
* Copyright (c) 2015 Bruno Medeiros and other Contributors.
* 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
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package info.elexis.server.core.p2.internal;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* @author Bruno Medeiros
* @see https://github.com/am2605/CfmlEclipseIDE
*/
public class TimeoutProgressMonitor implements IProgressMonitor {
protected int timeoutMillis;
protected long startTimeMillis = -1;
public TimeoutProgressMonitor(int timeoutMillis) {
this.timeoutMillis = timeoutMillis;
this.startTimeMillis = System.currentTimeMillis();
}
public int getTimeoutMillis() {
return timeoutMillis;
}
@Override
public void beginTask(String name, int totalWork) {
}
@Override
public boolean isCanceled() {
return System.currentTimeMillis() - startTimeMillis > timeoutMillis;
}
@Override
public void done() {
}
@Override
public void internalWorked(double work) {
}
@Override
public void setCanceled(boolean value) {
if(value) {
timeoutMillis = 0;
}
}
@Override
public void setTaskName(String name) {
}
@Override
public void subTask(String name) {
}
@Override
public void worked(int work) {
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/"/>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="lib/cron4j-2.2.5.jar" sourcepath="lib/cron4j-2.2.5-src.zip"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0" name="info.elexis.server.core.connector.elexis.ElexisConnectorManager">
<implementation class="info.elexis.server.core.connector.elexis.ElexisConnectorManager"/>
<reference name="ElexisConnector" interface="info.elexis.server.core.extension.IElexisConnector" cardinality="0..n" policy="static" bind="bind" unbind="unbind"/>
</scr:component>
package info.elexis.server.core.connector.elexis;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.event.Event;
import info.elexis.server.core.constants.ESEventConstants;
import info.elexis.server.core.extension.IElexisConnector;
import info.elexis.server.core.internal.Activator;
import info.elexis.server.core.internal.EventAdminConsumer;
@Component
public class ElexisConnectorManager {
private static IElexisConnector systemConnector;
private static List<IElexisConnector> elexisConnectors = new ArrayList<IElexisConnector>();
@Reference(
name = "ElexisConnector",
service = IElexisConnector.class,
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.STATIC,
unbind = "unbind"
)
protected synchronized void bind(IElexisConnector aec) {
elexisConnectors.add(aec);
}
protected synchronized void unbind(IElexisConnector aec) {
elexisConnectors.remove(aec);
}
public static List<IElexisConnector> getElexisConnectors() {
return elexisConnectors;
}
public static void setSystemConnector(IElexisConnector systemConnector) {
ElexisConnectorManager.systemConnector = systemConnector;
Event updateConfig = new Event(ESEventConstants.UPDATE_DB_CONNECTION, Collections.emptyMap());
EventAdminConsumer.getEventAdmin().sendEvent(updateConfig);
}
public static Optional<IElexisConnector> getElexisConnectorByClassName(String className) {
return ElexisConnectorManager.getElexisConnectors().stream()
.filter(p -> p.getClass().getName().equalsIgnoreCase(className)).findFirst();
}
public static IElexisConnector getSystemConnector() {
return systemConnector;
}
public static IStatus getConnectionStatusInformation() {
if (elexisConnectors.size() > 0) {
IElexisConnector ec = elexisConnectors.get(0);
return ec.getElexisDBStatusInformation();