Skip to main content
summaryrefslogtreecommitdiffstats
blob: feb6bb4d70abf2e1d17e885320e6eaba9efb6b22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*******************************************************************************
* Copyright (c) 2007, 2010 compeople AG 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
*
* Contributors:
* 	compeople AG (Stefan Liebig) - initial API and implementation
*  IBM - continuing development
*******************************************************************************/
package org.eclipse.equinox.internal.provisional.p2.artifact.repository.processing;

import java.io.OutputStream;
import java.util.ArrayList;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.artifact.repository.Activator;
import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository.ArtifactOutputStream;
import org.eclipse.equinox.internal.provisional.p2.repository.IStateful;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
import org.eclipse.equinox.p2.repository.artifact.IProcessingStepDescriptor;
import org.eclipse.osgi.util.NLS;

/**
 * Creates processing step instances from extensions and executes them.
 */
public class ProcessingStepHandler {

	private static final String PROCESSING_STEPS_EXTENSION_ID = "org.eclipse.equinox.p2.artifact.repository.processingSteps"; //$NON-NLS-1$

	//TODO This method can go
	public static IStatus checkStatus(OutputStream output) {
		return getStatus(output, true);
	}

	/**
	 * Check to see that we have processors for all the steps in the given descriptor
	 * @param descriptor the descriptor to check
	 * @return whether or not processors for all the descriptor's steps are installed
	 */
	public static boolean canProcess(IArtifactDescriptor descriptor) {
		IExtensionRegistry registry = RegistryFactory.getRegistry();
		IExtensionPoint point = registry.getExtensionPoint(PROCESSING_STEPS_EXTENSION_ID);
		if (point == null)
			return false;
		IProcessingStepDescriptor[] steps = descriptor.getProcessingSteps();
		for (int i = 0; i < steps.length; i++) {
			if (point.getExtension(steps[i].getProcessorId()) == null)
				return false;
		}
		return true;
	}

	/**
	 * Return the status of this step.  The status will be <code>null</code> if the
	 * step has not yet executed. If the step has executed the returned status
	 * indicates the success or failure of the step.
	 * @param deep whether or not to aggregate the status of any linked steps
	 * @return the requested status 
	 */
	public static IStatus getStatus(OutputStream stream, boolean deep) {
		if (!deep)
			return getStatus(stream);
		ArrayList<IStatus> list = new ArrayList<IStatus>();
		int severity = collectStatus(stream, list);
		if (severity == IStatus.OK)
			return Status.OK_STATUS;
		IStatus[] result = list.toArray(new IStatus[list.size()]);
		return new MultiStatus(Activator.ID, severity, result, Messages.processing_step_results, null);
	}

	/**
	 * Return statuses from this step and any linked step, discarding OK statuses until an error status is received.
	 * @param stream the stream representing the first step
	 * @return the requested status
	 */
	public static IStatus getErrorStatus(OutputStream stream) {
		ArrayList<IStatus> list = new ArrayList<IStatus>();
		int severity = collectErrorStatus(stream, list);
		if (severity == IStatus.OK)
			return Status.OK_STATUS;
		IStatus[] result = list.toArray(new IStatus[list.size()]);
		return new MultiStatus(Activator.ID, 0, result, Messages.processing_step_results, null);
	}

	private static int collectErrorStatus(OutputStream stream, ArrayList<IStatus> list) {
		IStatus status = getStatus(stream);
		if (!status.isOK())
			list.add(status);
		if (status.matches(IStatus.ERROR))
			// Errors past this should be bogus as they rely on output from this step
			return status.getSeverity();

		OutputStream destination = getDestination(stream);
		if (destination == null || !(destination instanceof IStateful))
			return status.getSeverity();
		int result = collectErrorStatus(destination, list);
		// TODO greater than test here is a little brittle but it is very unlikely that we will add
		// a new status severity.
		return status.getSeverity() > result ? status.getSeverity() : result;
	}

	public static IStatus getStatus(OutputStream stream) {
		if (stream instanceof IStateful)
			return ((IStateful) stream).getStatus();
		return Status.OK_STATUS;
	}

	private static int collectStatus(OutputStream stream, ArrayList<IStatus> list) {
		IStatus status = getStatus(stream);
		list.add(status);
		OutputStream destination = getDestination(stream);
		if (destination == null || !(destination instanceof IStateful))
			return status.getSeverity();
		int result = collectStatus(destination, list);
		// TODO greater than test here is a little brittle but it is very unlikely that we will add
		// a new status severity.
		return status.getSeverity() > result ? status.getSeverity() : result;
	}

	private static OutputStream getDestination(OutputStream stream) {
		if (stream instanceof ProcessingStep)
			return ((ProcessingStep) stream).getDestination();
		if (stream instanceof ArtifactOutputStream)
			return ((ArtifactOutputStream) stream).getDestination();
		return null;
	}

	public ProcessingStep[] create(IProvisioningAgent agent, IProcessingStepDescriptor[] descriptors, IArtifactDescriptor context) {
		ProcessingStep[] result = new ProcessingStep[descriptors.length];
		for (int i = 0; i < descriptors.length; i++)
			result[i] = create(agent, descriptors[i], context);
		return result;
	}

	public ProcessingStep create(IProvisioningAgent agent, IProcessingStepDescriptor descriptor, IArtifactDescriptor context) {
		IExtensionRegistry registry = RegistryFactory.getRegistry();
		IExtension extension = registry.getExtension(PROCESSING_STEPS_EXTENSION_ID, descriptor.getProcessorId());
		Exception error;
		if (extension != null) {
			IConfigurationElement[] config = extension.getConfigurationElements();
			try {
				Object object = config[0].createExecutableExtension("class"); //$NON-NLS-1$
				ProcessingStep step = (ProcessingStep) object;
				step.initialize(agent, descriptor, context);
				return step;
			} catch (Exception e) {
				error = e;
			}
		} else
			error = new ProcessingStepHandlerException(NLS.bind(Messages.cannot_get_extension, PROCESSING_STEPS_EXTENSION_ID, descriptor.getProcessorId()));

		int severity = descriptor.isRequired() ? IStatus.ERROR : IStatus.INFO;
		ProcessingStep result = new EmptyProcessingStep();
		result.setStatus(new Status(severity, Activator.ID, Messages.cannot_instantiate_step + descriptor.getProcessorId(), error));
		return result;
	}

	public OutputStream createAndLink(IProvisioningAgent agent, IProcessingStepDescriptor[] descriptors, IArtifactDescriptor context, OutputStream output, IProgressMonitor monitor) {
		if (descriptors == null)
			return output;
		ProcessingStep[] steps = create(agent, descriptors, context);
		return link(steps, output, monitor);
	}

	public OutputStream link(ProcessingStep[] steps, OutputStream output, IProgressMonitor monitor) {
		OutputStream previous = output;
		for (int i = steps.length - 1; i >= 0; i--) {
			ProcessingStep step = steps[i];
			step.link(previous, monitor);
			previous = step;
		}
		if (steps.length == 0)
			return previous;
		// now link the artifact stream to the first stream in the new chain 
		ArtifactOutputStream lastLink = getArtifactStream(previous);
		if (lastLink != null)
			lastLink.setFirstLink(previous);
		return previous;
	}

	// Traverse the chain of processing steps and return the stream served up by
	// the artifact repository or null if one cannot be found.
	private ArtifactOutputStream getArtifactStream(OutputStream stream) {
		OutputStream current = stream;
		while (current instanceof ProcessingStep)
			current = ((ProcessingStep) current).getDestination();
		if (current instanceof ArtifactOutputStream)
			return (ArtifactOutputStream) current;
		return null;
	}

	protected static final class EmptyProcessingStep extends ProcessingStep {
		// Just to hold the status
	}

	protected static final class ProcessingStepHandlerException extends Exception {
		private static final long serialVersionUID = 1L;

		public ProcessingStepHandlerException(String message) {
			super(message);
		}
	}
}

Back to the top