update copyright
[fedora-idea.git] / java / idea-ui / src / com / intellij / facet / impl / ui / libraries / LibraryDownloader.java
blobf4c799c51f53d45a35d7dec96eb103cc4c4cc1d9
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.facet.impl.ui.libraries;
19 import com.intellij.facet.ui.libraries.LibraryDownloadInfo;
20 import com.intellij.facet.ui.libraries.LibraryInfo;
21 import com.intellij.ide.IdeBundle;
22 import com.intellij.openapi.application.PathManager;
23 import com.intellij.openapi.application.Result;
24 import com.intellij.openapi.application.WriteAction;
25 import com.intellij.openapi.fileChooser.FileChooser;
26 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
27 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
28 import com.intellij.openapi.progress.ProcessCanceledException;
29 import com.intellij.openapi.progress.ProgressIndicator;
30 import com.intellij.openapi.progress.ProgressManager;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.ui.Messages;
33 import com.intellij.openapi.util.Pair;
34 import com.intellij.openapi.util.Ref;
35 import com.intellij.openapi.util.io.FileUtil;
36 import com.intellij.openapi.util.text.StringUtil;
37 import com.intellij.openapi.vfs.LocalFileSystem;
38 import com.intellij.openapi.vfs.VfsUtil;
39 import com.intellij.openapi.vfs.VirtualFile;
40 import com.intellij.openapi.vfs.VirtualFileManager;
41 import com.intellij.util.io.UrlConnectionUtil;
42 import com.intellij.util.net.HttpConfigurable;
43 import com.intellij.util.net.IOExceptionDialog;
44 import org.jetbrains.annotations.NonNls;
45 import org.jetbrains.annotations.NotNull;
46 import org.jetbrains.annotations.Nullable;
48 import javax.swing.*;
49 import java.io.*;
50 import java.net.HttpURLConnection;
51 import java.net.URL;
52 import java.util.ArrayList;
53 import java.util.List;
55 /**
56 * @author nik
58 public class LibraryDownloader {
59 private static final int CONNECTION_TIMEOUT = 60*1000;
60 private static final int READ_TIMEOUT = 60*1000;
61 @NonNls private static final String LIB_SCHEMA = "lib://";
63 private LibraryDownloadInfo[] myLibraryInfos;
64 private final LibraryDownloadingMirrorsMap myMirrorsMap;
65 private JComponent myParent;
66 private @Nullable Project myProject;
67 private String myDirectoryForDownloadedLibrariesPath;
68 private final @Nullable String myLibraryPresentableName;
70 public LibraryDownloader(final LibraryDownloadInfo[] libraryInfos, final @Nullable Project project, JComponent parent, @Nullable String directoryForDownloadedLibrariesPath,
71 @Nullable String libraryPresentableName,
72 final LibraryDownloadingMirrorsMap mirrorsMap) {
73 myProject = project;
74 myLibraryInfos = libraryInfos;
75 myParent = parent;
76 myDirectoryForDownloadedLibrariesPath = directoryForDownloadedLibrariesPath;
77 myLibraryPresentableName = libraryPresentableName;
78 myMirrorsMap = mirrorsMap;
81 public LibraryDownloader(final LibraryDownloadInfo[] libraryInfos, final @Nullable Project project, @NotNull JComponent parent) {
82 this(libraryInfos, project, parent, null, null, new LibraryDownloadingMirrorsMap());
85 public LibraryDownloader(final LibraryDownloadInfo[] libraryInfos, final @NotNull Project project) {
86 myLibraryInfos = libraryInfos;
87 myProject = project;
88 myLibraryPresentableName = null;
89 myMirrorsMap = new LibraryDownloadingMirrorsMap();
92 public VirtualFile[] download() {
93 VirtualFile dir = null;
94 if (myDirectoryForDownloadedLibrariesPath != null) {
95 File ioDir = new File(FileUtil.toSystemDependentName(myDirectoryForDownloadedLibrariesPath));
96 ioDir.mkdirs();
97 dir = LocalFileSystem.getInstance().refreshAndFindFileByPath(myDirectoryForDownloadedLibrariesPath);
100 if (dir == null) {
101 dir = chooseDirectoryForLibraries();
104 if (dir != null) {
105 return doDownload(dir);
107 return VirtualFile.EMPTY_ARRAY;
110 private VirtualFile[] doDownload(final VirtualFile dir) {
111 HttpConfigurable.getInstance().setAuthenticator();
112 final List<Pair<LibraryDownloadInfo, File>> downloadedFiles = new ArrayList<Pair<LibraryDownloadInfo, File>>();
113 final List<VirtualFile> existingFiles = new ArrayList<VirtualFile>();
114 final Ref<Exception> exceptionRef = Ref.create(null);
115 final Ref<LibraryDownloadInfo> currentLibrary = new Ref<LibraryDownloadInfo>();
117 String dialogTitle = IdeBundle.message("progress.download.libraries.title");
118 if (myLibraryPresentableName != null) {
119 dialogTitle = IdeBundle.message("progress.download.0.libraries.title", StringUtil.capitalize(myLibraryPresentableName));
122 ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
123 public void run() {
124 final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
125 try {
126 for (int i = 0; i < myLibraryInfos.length; i++) {
127 LibraryDownloadInfo info = myLibraryInfos[i];
128 currentLibrary.set(info);
129 if (indicator != null) {
130 indicator.checkCanceled();
131 indicator.setText(IdeBundle.message("progress.0.of.1.file.downloaded.text", i, myLibraryInfos.length));
134 final VirtualFile existing = dir.findChild(getExpectedFileName(info));
135 long size = existing != null ? existing.getLength() : -1;
137 if (!download(info, size, downloadedFiles)) {
138 existingFiles.add(existing);
142 catch (ProcessCanceledException e) {
143 exceptionRef.set(e);
145 catch (IOException e) {
146 exceptionRef.set(e);
149 }, dialogTitle, true, myProject, myParent);
151 Exception exception = exceptionRef.get();
152 if (exception == null) {
153 try {
154 return moveToDir(existingFiles, downloadedFiles, dir);
156 catch (IOException e) {
157 final String title = IdeBundle.message("progress.download.libraries.title");
158 if (myProject != null) {
159 Messages.showErrorDialog(myProject, title, e.getMessage());
161 else {
162 Messages.showErrorDialog(myParent, title, e.getMessage());
164 return VirtualFile.EMPTY_ARRAY;
168 deleteFiles(downloadedFiles);
169 if (exception instanceof IOException) {
170 String message = IdeBundle.message("error.library.download.failed", exception.getMessage());
171 if (currentLibrary.get() != null) {
172 message += ": " + myMirrorsMap.getDownloadingUrl(currentLibrary.get());
174 final boolean tryAgain = IOExceptionDialog.showErrorDialog(IdeBundle.message("progress.download.libraries.title"), message);
175 if (tryAgain) {
176 return doDownload(dir);
179 return VirtualFile.EMPTY_ARRAY;
182 private @Nullable VirtualFile chooseDirectoryForLibraries() {
183 final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
184 descriptor.setTitle(IdeBundle.message("dialog.directory.for.libraries.title"));
186 final VirtualFile[] files;
187 if (myProject != null) {
188 files = FileChooser.chooseFiles(myProject, descriptor, myProject.getBaseDir());
190 else {
191 files = FileChooser.chooseFiles(myParent, descriptor);
194 return files.length > 0 ? files[0] : null;
197 private static VirtualFile[] moveToDir(final List<VirtualFile> existingFiles, final List<Pair<LibraryDownloadInfo, File>> downloadedFiles, final VirtualFile dir) throws IOException {
198 List<VirtualFile> files = new ArrayList<VirtualFile>();
200 final File ioDir = VfsUtil.virtualToIoFile(dir);
201 for (Pair<LibraryDownloadInfo, File> pair : downloadedFiles) {
202 final LibraryDownloadInfo info = pair.getFirst();
203 final boolean dontTouch = info.getDownloadUrl().startsWith(LIB_SCHEMA) || info.getDownloadUrl().startsWith(LocalFileSystem.PROTOCOL_PREFIX);
204 final File toFile = dontTouch? pair.getSecond() : generateName(info, ioDir);
205 if (!dontTouch) {
206 FileUtil.rename(pair.getSecond(), toFile);
208 VirtualFile file = new WriteAction<VirtualFile>() {
209 protected void run(final Result<VirtualFile> result) {
210 final String url = VfsUtil.getUrlForLibraryRoot(toFile);
211 LocalFileSystem.getInstance().refreshAndFindFileByIoFile(toFile);
212 result.setResult(VirtualFileManager.getInstance().refreshAndFindFileByUrl(url));
214 }.execute().getResultObject();
215 if (file != null) {
216 files.add(file);
220 for (final VirtualFile file : existingFiles) {
221 VirtualFile libraryRootFile = new WriteAction<VirtualFile>() {
222 protected void run(final Result<VirtualFile> result) {
223 final String url = VfsUtil.getUrlForLibraryRoot(VfsUtil.virtualToIoFile(file));
224 result.setResult(VirtualFileManager.getInstance().refreshAndFindFileByUrl(url));
227 }.execute().getResultObject();
228 if (libraryRootFile != null) {
229 files.add(libraryRootFile);
233 return files.toArray(new VirtualFile[files.size()]);
236 private static String getExpectedFileName(LibraryDownloadInfo info) {
237 return info.getFileNamePrefix() + info.getFileNameSuffix();
240 private static File generateName(LibraryDownloadInfo info, final File dir) {
241 String prefix = info.getFileNamePrefix();
242 String suffix = info.getFileNameSuffix();
243 File file = new File(dir, prefix + suffix);
244 int count = 1;
245 while (file.exists()) {
246 file = new File(dir, prefix + "_" + count + suffix);
247 count++;
249 return file;
252 private static void deleteFiles(final List<Pair<LibraryDownloadInfo, File>> pairs) {
253 for (Pair<LibraryDownloadInfo, File> pair : pairs) {
254 FileUtil.delete(pair.getSecond());
256 pairs.clear();
259 private boolean download(final LibraryDownloadInfo libraryInfo, final long existingFileSize, final List<Pair<LibraryDownloadInfo, File>> downloadedFiles) throws IOException {
260 final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
261 final String presentableUrl = myMirrorsMap.getPresentableUrl(libraryInfo);
262 final String url = myMirrorsMap.getDownloadingUrl(libraryInfo);
263 if (url.startsWith(LIB_SCHEMA)) {
264 indicator.setText2(IdeBundle.message("progress.locate.jar.text", getExpectedFileName(libraryInfo)));
265 final String path = url.substring(LIB_SCHEMA.length()).replace('/', File.separatorChar);
266 final File file = PathManager.findFileInLibDirectory(path);
267 downloadedFiles.add(Pair.create(libraryInfo, file));
268 } else if (url.startsWith(LocalFileSystem.PROTOCOL_PREFIX)) {
269 String path = url.substring(LocalFileSystem.PROTOCOL_PREFIX.length()).replace('/', File.separatorChar).replace('\\', File.separatorChar);
270 File file = new File(path);
271 if (file.exists()) downloadedFiles.add(Pair.create(libraryInfo, file));
272 } else {
273 indicator.setText2(IdeBundle.message("progress.connecting.to.dowload.jar.text", presentableUrl));
274 indicator.setIndeterminate(true);
275 HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection();
276 connection.setConnectTimeout(CONNECTION_TIMEOUT);
277 connection.setReadTimeout(READ_TIMEOUT);
279 InputStream input = null;
280 BufferedOutputStream output = null;
282 boolean deleteFile = true;
283 File tempFile = null;
284 try {
285 final int responseCode = connection.getResponseCode();
286 if (responseCode != HttpURLConnection.HTTP_OK) {
287 throw new IOException(IdeBundle.message("error.connection.failed.with.http.code.N", responseCode));
290 final int size = connection.getContentLength();
291 if (size != -1 && size == existingFileSize) {
292 return false;
295 tempFile = FileUtil.createTempFile("downloaded", "jar");
296 input = UrlConnectionUtil.getConnectionInputStreamWithException(connection, indicator);
297 output = new BufferedOutputStream(new FileOutputStream(tempFile));
298 indicator.setText2(IdeBundle.message("progress.download.jar.text", getExpectedFileName(libraryInfo), presentableUrl));
299 indicator.setIndeterminate(size == -1);
301 int len;
302 final byte[] buf = new byte[1024];
303 int count = 0;
304 while ((len = input.read(buf)) > 0) {
305 indicator.checkCanceled();
306 count += len;
307 if (size > 0) {
308 indicator.setFraction((double)count / size);
310 output.write(buf, 0, len);
313 deleteFile = false;
314 downloadedFiles.add(Pair.create(libraryInfo, tempFile));
316 finally {
317 if (input != null) {
318 input.close();
320 if (output != null) {
321 output.close();
323 if (deleteFile && tempFile != null) {
324 FileUtil.delete(tempFile);
326 connection.disconnect();
329 return true;
332 public static LibraryDownloadInfo[] getDownloadingInfos(final LibraryInfo[] libraries) {
333 List<LibraryDownloadInfo> downloadInfos = new ArrayList<LibraryDownloadInfo>();
334 for (LibraryInfo library : libraries) {
335 LibraryDownloadInfo downloadInfo = library.getDownloadingInfo();
336 if (downloadInfo != null) {
337 downloadInfos.add(downloadInfo);
340 return downloadInfos.toArray(new LibraryDownloadInfo[downloadInfos.size()]);