1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.repository.internal.resources

File ExtensionVersionFileRESTResource.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart6.png
69% of files have more coverage

Code metrics

20
71
3
1
253
178
18
0.25
23.67
3
6

Classes

Class Line # Actions
ExtensionVersionFileRESTResource 83 71 0% 18 40
0.574468157.4%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.repository.internal.resources;
21   
22    import java.io.IOException;
23    import java.net.ProxySelector;
24    import java.net.URI;
25    import java.net.URISyntaxException;
26    import java.net.URL;
27   
28    import javax.inject.Inject;
29    import javax.inject.Named;
30    import javax.inject.Singleton;
31    import javax.ws.rs.GET;
32    import javax.ws.rs.Path;
33    import javax.ws.rs.PathParam;
34    import javax.ws.rs.QueryParam;
35    import javax.ws.rs.WebApplicationException;
36    import javax.ws.rs.core.Response;
37    import javax.ws.rs.core.Response.ResponseBuilder;
38    import javax.ws.rs.core.Response.Status;
39   
40    import org.apache.http.HttpEntity;
41    import org.apache.http.HttpResponse;
42    import org.apache.http.client.methods.HttpGet;
43    import org.apache.http.impl.client.DefaultHttpClient;
44    import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
45    import org.apache.http.params.CoreConnectionPNames;
46    import org.apache.http.params.CoreProtocolPNames;
47    import org.restlet.data.Disposition;
48    import org.restlet.data.MediaType;
49    import org.restlet.representation.InputRepresentation;
50    import org.xwiki.component.annotation.Component;
51    import org.xwiki.extension.Extension;
52    import org.xwiki.extension.ExtensionFile;
53    import org.xwiki.extension.ExtensionId;
54    import org.xwiki.extension.ResolveException;
55    import org.xwiki.extension.repository.DefaultExtensionRepositoryDescriptor;
56    import org.xwiki.extension.repository.ExtensionRepository;
57    import org.xwiki.extension.repository.ExtensionRepositoryDescriptor;
58    import org.xwiki.extension.repository.ExtensionRepositoryFactory;
59    import org.xwiki.extension.repository.ExtensionRepositoryManager;
60    import org.xwiki.model.reference.AttachmentReference;
61    import org.xwiki.model.reference.AttachmentReferenceResolver;
62    import org.xwiki.query.QueryException;
63    import org.xwiki.rendering.listener.reference.ResourceReference;
64    import org.xwiki.rendering.listener.reference.ResourceType;
65    import org.xwiki.repository.Resources;
66    import org.xwiki.repository.internal.XWikiRepositoryModel;
67    import org.xwiki.repository.internal.reference.ExtensionResourceReference;
68   
69    import com.xpn.xwiki.XWikiContext;
70    import com.xpn.xwiki.XWikiException;
71    import com.xpn.xwiki.doc.XWikiAttachment;
72    import com.xpn.xwiki.doc.XWikiDocument;
73    import com.xpn.xwiki.objects.BaseObject;
74   
75    /**
76    * @version $Id: 190543cdfe4ab6b4a30b9cf2a5828ad056339f57 $
77    * @since 3.2M3
78    */
79    @Component
80    @Named("org.xwiki.repository.internal.resources.ExtensionVersionFileRESTResource")
81    @Path(Resources.EXTENSION_VERSION_FILE)
82    @Singleton
 
83    public class ExtensionVersionFileRESTResource extends AbstractExtensionRESTResource
84    {
85    @Inject
86    private AttachmentReferenceResolver<String> attachmentResolver;
87   
88    @Inject
89    private ExtensionRepositoryManager extensionRepositoryManager;
90   
 
91  20 toggle @GET
92    public Response downloadExtension(@PathParam(Resources.PPARAM_EXTENSIONID) String extensionId,
93    @PathParam(Resources.PPARAM_EXTENSIONVERSION) String extensionVersion,
94    @QueryParam(ExtensionResourceReference.PARAM_REPOSITORYID) String repositoryId,
95    @QueryParam(ExtensionResourceReference.PARAM_REPOSITORYTYPE) String repositoryType,
96    @QueryParam(ExtensionResourceReference.PARAM_REPOSITORYURI) String repositoryURI)
97    throws XWikiException, QueryException, URISyntaxException, IOException, ResolveException
98    {
99  20 ResponseBuilder response;
100   
101  20 if (repositoryId != null) {
102  0 response =
103    downloadRemoteExtension(new ExtensionResourceReference(extensionId, extensionVersion, repositoryId));
104  20 } else if (repositoryType != null && repositoryURI != null) {
105  0 response = downloadRemoteExtension(
106    new ExtensionResourceReference(extensionId, extensionVersion, repositoryType, new URI(repositoryURI)));
107    } else {
108  20 response = downloadLocalExtension(extensionId, extensionVersion);
109    }
110   
111  20 return response.build();
112    }
113   
 
114  20 toggle private ResponseBuilder downloadLocalExtension(String extensionId, String extensionVersion)
115    throws ResolveException, IOException, QueryException, XWikiException
116    {
117  20 XWikiDocument extensionDocument = getExistingExtensionDocumentById(extensionId);
118   
119  20 checkRights(extensionDocument);
120   
121  20 BaseObject extensionObject = getExtensionObject(extensionDocument);
122  20 BaseObject extensionVersionObject = getExtensionVersionObject(extensionDocument, extensionVersion);
123   
124  20 ResponseBuilder response = null;
125   
126  20 ResourceReference resourceReference =
127    this.repositoryManager.getDownloadReference(extensionDocument, extensionVersionObject);
128   
129  20 if (ResourceType.ATTACHMENT.equals(resourceReference.getType())) {
130    // It's an attachment
131  17 AttachmentReference attachmentReference = this.attachmentResolver.resolve(resourceReference.getReference(),
132    extensionDocument.getDocumentReference());
133   
134  17 XWikiContext xcontext = getXWikiContext();
135   
136  17 XWikiDocument document =
137    xcontext.getWiki().getDocument(attachmentReference.getDocumentReference(), xcontext);
138   
139  17 checkRights(document);
140   
141  17 XWikiAttachment xwikiAttachment = document.getAttachment(attachmentReference.getName());
142   
143  17 response = getAttachmentResponse(xwikiAttachment);
144  3 } else if (ResourceType.URL.equals(resourceReference.getType())) {
145    // It's an URL
146  0 URL url = new URL(resourceReference.getReference());
147   
148  0 DefaultHttpClient httpClient = new DefaultHttpClient();
149   
150  0 httpClient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "XWikiExtensionRepository");
151  0 httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 60000);
152  0 httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);
153   
154  0 ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
155    httpClient.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
156  0 httpClient.setRoutePlanner(routePlanner);
157   
158  0 HttpGet getMethod = new HttpGet(url.toString());
159   
160  0 HttpResponse subResponse;
161  0 try {
162  0 subResponse = httpClient.execute(getMethod);
163    } catch (Exception e) {
164  0 throw new IOException("Failed to request [" + getMethod.getURI() + "]", e);
165    }
166   
167  0 response = Response.status(subResponse.getStatusLine().getStatusCode());
168   
169    // TODO: find a proper way to do a perfect proxy of the URL without directly using Restlet classes.
170    // Should probably use javax.ws.rs.ext.MessageBodyWriter
171  0 HttpEntity entity = subResponse.getEntity();
172  0 InputRepresentation content =
173    new InputRepresentation(
174  0 entity.getContent(), entity.getContentType() != null
175    ? new MediaType(entity.getContentType().getValue()) : MediaType.APPLICATION_OCTET_STREAM,
176    entity.getContentLength());
177   
178  0 String type = getValue(extensionObject, XWikiRepositoryModel.PROP_EXTENSION_TYPE);
179   
180  0 Disposition disposition = new Disposition(Disposition.TYPE_ATTACHMENT);
181  0 disposition.setFilename(extensionId + '-' + extensionVersion + '.' + type);
182  0 content.setDisposition(disposition);
183   
184  0 response.entity(content);
185  3 } else if (ExtensionResourceReference.TYPE.equals(resourceReference.getType())) {
186  3 ExtensionResourceReference extensionResource;
187  3 if (resourceReference instanceof ExtensionResourceReference) {
188  3 extensionResource = (ExtensionResourceReference) resourceReference;
189    } else {
190  0 extensionResource = new ExtensionResourceReference(resourceReference.getReference());
191    }
192   
193  3 response = downloadRemoteExtension(extensionResource);
194    } else {
195  0 throw new WebApplicationException(Status.NOT_FOUND);
196    }
197   
198  20 return response;
199    }
200   
 
201  3 toggle private ResponseBuilder downloadRemoteExtension(ExtensionResourceReference extensionResource)
202    throws ResolveException, IOException
203    {
204  3 ExtensionRepository repository = null;
205  3 if (extensionResource.getRepositoryId() != null) {
206  3 repository = this.extensionRepositoryManager.getRepository(extensionResource.getRepositoryId());
207    }
208   
209  3 if (repository == null && extensionResource.getRepositoryType() != null
210    && extensionResource.getRepositoryURI() != null) {
211  0 ExtensionRepositoryDescriptor repositoryDescriptor = new DefaultExtensionRepositoryDescriptor("tmp",
212    extensionResource.getRepositoryType(), extensionResource.getRepositoryURI());
213  0 try {
214  0 ExtensionRepositoryFactory repositoryFactory =
215    this.componentManager.getInstance(ExtensionRepositoryFactory.class, repositoryDescriptor.getType());
216   
217  0 repository = repositoryFactory.createRepository(repositoryDescriptor);
218    } catch (Exception e) {
219    // Ignore invalid repository
220  0 this.logger.warning("Invalid repository in download link [" + extensionResource + "]");
221    }
222   
223    }
224   
225    // Resolve extension
226  3 Extension downloadExtension;
227  3 if (repository == null) {
228  0 downloadExtension = this.extensionRepositoryManager
229    .resolve(new ExtensionId(extensionResource.getExtensionId(), extensionResource.getExtensionVersion()));
230    } else {
231  3 downloadExtension = repository
232    .resolve(new ExtensionId(extensionResource.getExtensionId(), extensionResource.getExtensionVersion()));
233    }
234   
235    // Get file
236    // TODO: find media type
237  3 ExtensionFile extensionFile = downloadExtension.getFile();
238  3 long length = extensionFile.getLength();
239   
240    // TODO: find a proper way to do a perfect proxy of the URL without directly using Restlet classes.
241    // Should probably use javax.ws.rs.ext.MessageBodyWriter
242  3 InputRepresentation content = new InputRepresentation(extensionFile.openStream(), MediaType.ALL, length);
243   
244  3 Disposition disposition = new Disposition(Disposition.TYPE_ATTACHMENT);
245  3 disposition.setFilename(downloadExtension.getId().toString() + '.' + downloadExtension.getType());
246  3 content.setDisposition(disposition);
247   
248  3 ResponseBuilder response = Response.ok();
249  3 response.entity(content);
250   
251  3 return response;
252    }
253    }