/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed 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.wso2.carbon.component.mgt.core.profile;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.provisional.p2.director.IPlanner;
import org.eclipse.equinox.internal.provisional.p2.director.ProfileChangeRequest;
import org.eclipse.equinox.internal.provisional.p2.director.ProvisioningPlan;
import org.eclipse.equinox.internal.provisional.p2.director.RequestStatus;
import org.eclipse.equinox.internal.provisional.p2.engine.IEngine;
import org.eclipse.equinox.internal.provisional.p2.engine.IProfile;
import org.eclipse.equinox.internal.provisional.p2.engine.ProvisioningContext;
import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit;
import org.wso2.carbon.component.mgt.core.ProvisioningException;
import org.wso2.carbon.component.mgt.core.ResolutionResult;
import org.wso2.carbon.component.mgt.core.internal.ServiceHolder;
import java.text.NumberFormat;
import java.util.Map;
public abstract class ProfileModificationAction {
private String actionType;
/**
* Indicates that the size is currently unknown
*/
public static final long SIZE_UNKNOWN = -1L;
/**
* Indicates that the size is unavailable (an
* attempt was made to compute size but it failed)
*/
public static final long SIZE_UNAVAILABLE = -2L;
/**
* Indicates that there was nothing to size (there
* was no valid plan that could be used to compute
* size).
*/
public static final long SIZE_NOTAPPLICABLE = -3L;
protected IInstallableUnit[] iusToInstall;
public IInstallableUnit[] getIusToInstall() {
return iusToInstall;
}
public void setIusToInstall(IInstallableUnit[] iusToInstall) {
this.iusToInstall = iusToInstall;
}
public IInstallableUnit[] getIusToUninstall() {
return iusToUninstall;
}
public void setIusToUninstall(IInstallableUnit[] iusToUninstall) {
this.iusToUninstall = iusToUninstall;
}
protected IInstallableUnit[] iusToUninstall;
protected long timestamp;
public ProfileModificationAction(String actionType) {
this.actionType = actionType;
}
public ResolutionResult reviewProfileChangeAction(IProfile profile) throws ProvisioningException {
MultiStatus initialStatus = getInitialStatus();
ProfileChangeRequest profileChangeRequest = generateProfileChangeRequest(
profile, initialStatus, null);
ProvisioningPlan provisioningPlan = generateProvisioningPlan(profileChangeRequest);
if (provisioningPlan == null) {
throw new ProvisioningException("Failed to generate the Provisioning Plan");
}
return generateResolutionResult(profileChangeRequest, provisioningPlan, initialStatus);
}
public ResolutionResult generateResolutionResult(ProfileChangeRequest originalRequest,
ProvisioningPlan plan,
MultiStatus originalStatus)
throws ProvisioningException {
IEngine engine = ServiceHolder.getP2Engine();
ResolutionResult report = new ResolutionResult();
report.setProvisioningPlan(plan);
if (nothingToDo(originalRequest)) {
report.addSummaryStatus(new Status(IStatus.ERROR, "temp", 10050,
"Cannot complete the request. See the error log for details.", null));
IStatus[] details = originalStatus.getChildren();
for (IStatus detail : details) {
report.addSummaryStatus(detail);
}
return report;
}
// If there was already some status supplied before resolution, this should get included
// with the report.
if (originalStatus != null && originalStatus.getChildren().length > 0) {
report.addSummaryStatus(originalStatus);
}
// If the overall plan had a non-OK status, capture that in the report.
if (!plan.getStatus().isOK()) {
report.addSummaryStatus(plan.getStatus());
}
// Now we compare what was requested with what is going to happen.
if (plan.getStatus().getSeverity() != IStatus.ERROR) {
IInstallableUnit[] iusAdded = originalRequest.getAddedInstallableUnits();
for (IInstallableUnit anIusAdded : iusAdded) {
RequestStatus rs = plan.getRequestStatus(anIusAdded);
if (rs.getSeverity() == IStatus.ERROR) {
// This is a serious error so it must also appear in the overall status
IStatus fail = new Status(IStatus.ERROR, "temp", 10011, anIusAdded.getId() +
" is not applicable to the current configuration and will not be installed.", null);
report.addStatus(anIusAdded, fail);
report.addSummaryStatus(fail);
report.addFailedInstallableUnit(anIusAdded);
} else {
report.addReviewedInstallableUnit(anIusAdded);
}
}
IInstallableUnit[] iusRemoved = originalRequest.getRemovedInstallableUnits();
for (IInstallableUnit anIusRemoved : iusRemoved) {
RequestStatus rs = plan.getRequestStatus(anIusRemoved);
if (rs.getSeverity() == IStatus.ERROR) {
// We are making assumptions here about why the planner chose to ignore an uninstall.
IStatus fail = new Status(IStatus.INFO, "temp", 10007, anIusRemoved.getId() +
" cannot be fully uninstalled because other installed software requires it. " +
"The parts that are not required will be uninstalled.", null);
report.addStatus(anIusRemoved, fail);
report.addSummaryStatus(fail);
report.addFailedUninstallableUnit(anIusRemoved);
} else {
report.addReviewedUninstallableUnit(anIusRemoved);
}
}
}
// Now process the side effects
Map sideEffects = plan.getSideEffectChanges();
for (Object o : sideEffects.keySet()) {
IInstallableUnit iu = (IInstallableUnit) o;
RequestStatus rs = (RequestStatus) sideEffects.get(iu);
if (rs.getInitialRequestType() == RequestStatus.ADDED) {
report.addStatus(iu, new Status(rs.getSeverity(), "temp", 10010, iu.getId() +
" will also be installed in order to complete this operation.", null));
report.addReviewedInstallableUnit(iu);
} else {
report.addStatus(iu, new Status(rs.getSeverity(), "temp", 10009, iu.getId() +
" must be uninstalled in order to complete this operation.", null));
report.addReviewedUninstallableUnit(iu);
}
}
long size = 0;
if (report.getReviewedInstallableUnits().length != 0) {
size = getSize(plan,
plan.getProfileChangeRequest().getProfile(), engine, new ProvisioningContext(), null);
}
report.setInstallationSize(getFormattedSize(size));
return report;
}
public String getActionType() {
return actionType;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public abstract ProfileChangeRequest generateProfileChangeRequest(IProfile profile,
MultiStatus status, IProgressMonitor monitor);
public abstract long getSize(
ProvisioningPlan plan, IProfile profile, IEngine engine,
ProvisioningContext context, IProgressMonitor monitor);
public abstract MultiStatus getInitialStatus();
private ProvisioningPlan generateProvisioningPlan(ProfileChangeRequest profileChangeRequest)
throws ProvisioningException {
IPlanner planner = ServiceHolder.getPlanner();
ProvisioningContext context = new ProvisioningContext();
return planner.getProvisioningPlan(profileChangeRequest, context, new NullProgressMonitor());
}
private static boolean nothingToDo(ProfileChangeRequest request) {
return request.getAddedInstallableUnits().length == 0 && request.getRemovedInstallableUnits().length == 0 &&
request.getInstallableUnitProfilePropertiesToAdd().size() == 0 &&
request.getInstallableUnitProfilePropertiesToRemove().size() == 0;
}
private String getFormattedSize(long size) {
if (size == SIZE_UNKNOWN || size == SIZE_UNAVAILABLE) {
return "Unknown";
}
if (size > 1000L) {
long kb = size / 1000L;
return NumberFormat.getInstance().format(kb) + " kb";
}
return NumberFormat.getInstance().format(size);
}
}