/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2014 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
* Contributor(s):
*
* Portions Copyrighted 2014 Sun Microsystems, Inc.
*/
package com.junichi11.netbeans.modules.github.issues;
import com.junichi11.netbeans.modules.github.issues.repository.GitHubRepository;
import com.junichi11.netbeans.modules.github.issues.utils.StringUtils;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.eclipse.egit.github.core.Label;
import org.eclipse.egit.github.core.Milestone;
import org.eclipse.egit.github.core.Repository;
import org.eclipse.egit.github.core.RepositoryBranch;
import org.eclipse.egit.github.core.User;
import org.eclipse.egit.github.core.client.GitHubClient;
import org.eclipse.egit.github.core.service.CollaboratorService;
import org.eclipse.egit.github.core.service.LabelService;
import org.eclipse.egit.github.core.service.MilestoneService;
import org.eclipse.egit.github.core.service.RepositoryService;
import org.eclipse.egit.github.core.service.UserService;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
/**
* Cached data via GitHub API.
*
* @author junichi11
*/
public final class GitHubCache {
// @GuardedBy("this")
private static final Map<String, GitHubCache> CACHES = Collections.synchronizedMap(new HashMap<String, GitHubCache>());
// @GuardedBy("this")
private List<User> collaborators;
// @GuardedBy("this")
private final Map<String, List<Milestone>> milestoneMap = Collections.synchronizedMap(new HashMap<String, List<Milestone>>());
// @GuardedBy("this")
private List<Label> labels;
// @GuardedBy("this")
private List<RepositoryBranch> branches;
// @GuardedBy("this")
private List<Repository> forks;
private User myself;
// @GuardedBy("this")
private final Map<String, Icon> userIcons = new HashMap<>();
private final GitHubRepository repository;
private static final Logger LOGGER = Logger.getLogger(GitHubCache.class.getName());
// <OAuth token, User>
private static final Map<String, User> USERS = Collections.synchronizedMap(new HashMap<String, User>());
private GitHubCache(GitHubRepository repository) {
this.repository = repository;
}
/**
* Create GitHubCache.
*
* @param repository GitHubRepository
* @return GitHubCache
*/
public static synchronized GitHubCache create(@NonNull GitHubRepository repository) {
String id = repository.getID();
GitHubCache cache = CACHES.get(id);
if (cache != null) {
return cache;
}
cache = new GitHubCache(repository);
CACHES.put(id, cache);
return cache;
}
/**
* Clear cache for specified repository.
*
* @param repository GitHubRepository
*/
public synchronized void clear(GitHubRepository repository) {
CACHES.remove(repository.getID());
}
/**
* Get collaborators. <i>Note</i> Require the push access.
*
* @return collaborators
*/
public synchronized List<User> getCollaborators() {
if (collaborators == null) {
Repository ghRepository = repository.getRepository();
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return Collections.emptyList();
}
CollaboratorService collaboratorService = new CollaboratorService(client);
try {
collaborators = collaboratorService.getCollaborators(ghRepository);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "{0} : Can''t get collaborators. {1}", new Object[]{repository.getFullName(), ex.getMessage()}); // NOI18N
}
}
return collaborators;
}
/**
* Get milestones. If there is a cache, it is returned.
*
* @param state open, closed or all
* @return milestones
*/
public List<Milestone> getMilestones(String state) {
return getMilestones(state, false);
}
/**
* Get milestones.
*
* @param state open, closed or all
* @param force {@code true} if don't use cache data, otherwise
* {@code false}
* @return milestones
*/
public synchronized List<Milestone> getMilestones(String state, boolean force) {
List<Milestone> milestone = milestoneMap.get(state);
if (milestone == null || force) {
if (milestone != null) {
milestone.clear();
}
Repository gHRepository = repository.getRepository();
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return Collections.emptyList();
}
MilestoneService milestoneService = new MilestoneService(client);
try {
milestone = milestoneService.getMilestones(gHRepository, state);
milestoneMap.put(state, milestone);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "{0} : Can''t get milestones. {1}", new Object[]{repository.getFullName(), ex.getMessage()}); // NOI18N
}
}
return milestone;
}
/**
* Get labels. If there is a cache, it is returned.
*
* @return labels
*/
public List<Label> getLabels() {
return getLabels(false);
}
/**
* Get labels.
*
* @param force {@code true} if reload labels, otherwise {@code false}
* @return labels
*/
public synchronized List<Label> getLabels(boolean force) {
if (labels == null || force) {
if (labels != null) {
labels.clear();
}
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return Collections.emptyList();
}
LabelService labelService = new LabelService(client);
Repository ghRepository = repository.getRepository();
try {
labels = labelService.getLabels(ghRepository);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "{0} : Can''t get labels. {1}", new Object[]{repository.getFullName(), ex.getMessage()}); // NOI18N
}
}
return labels;
}
/**
* Get myself.
*
* @return myself
*/
@CheckForNull
public synchronized User getMySelf() {
if (myself == null) {
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return null;
}
UserService userService = new UserService(client);
try {
myself = userService.getUser();
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "{0} : Can''t get myself. {1}", new Object[]{repository.getFullName(), ex.getMessage()}); // NOI18N
}
}
return myself;
}
/**
* Get user icon. Icon size is 16x16.
*
* @param user User
* @return user icon if it was got, otherwise {@code null}
*/
@CheckForNull
public synchronized Icon getUserIcon(User user) {
if (user == null) {
return null;
}
String login = user.getLogin();
Icon icon = userIcons.get(login);
if (icon != null) {
return icon;
}
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return null;
}
UserService userService = new UserService(client);
try {
user = userService.getUser(login);
String avatarUrl = user.getAvatarUrl();
if (avatarUrl != null && !avatarUrl.isEmpty()) {
URL url = new URL(avatarUrl);
// resize to 16x16
BufferedImage image = ImageIO.read(url);
Image resizedImage = image.getScaledInstance(16, 16, Image.SCALE_SMOOTH);
icon = new ImageIcon(resizedImage);
userIcons.put(login, icon);
return icon;
}
} catch (IOException ex) {
LOGGER.log(Level.WARNING, ex.getMessage());
}
return null;
}
/**
* Get branches on a repository. Get them from a cache.
*
* @return RepositoryBranches
*/
public List<RepositoryBranch> getBranches() {
return getBranches(false);
}
/**
* Get branches on a repository.
*
* @param force {@code true} if reload branches, otherwise {@code false}
* @return RepositoryBranches
*/
public synchronized List<RepositoryBranch> getBranches(boolean force) {
if (branches == null || force) {
if (branches != null) {
branches.clear();
}
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return Collections.emptyList();
}
RepositoryService service = new RepositoryService(client);
Repository ghRepository = repository.getRepository();
try {
branches = service.getBranches(ghRepository);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "{0} : Can''t get branches. {1}", new Object[]{repository.getFullName(), ex.getMessage()}); // NOI18N
}
}
return branches;
}
/**
* Get forks for a repository. If there is a cache, it is returned.
*
* @return forks
*/
public List<Repository> getForks() {
return getForks(false);
}
/**
* Get forks for a repository.
*
* @param force {@code true} if don't use the cache, otherwise {@code false}
* @return forks
*/
public synchronized List<Repository> getForks(boolean force) {
if (forks == null || force) {
if (forks != null) {
forks.clear();
}
GitHubClient client = repository.createGitHubClient();
if (client == null) {
return Collections.emptyList();
}
RepositoryService service = new RepositoryService(client);
Repository ghRepository = repository.getRepository();
try {
forks = service.getForks(ghRepository);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "{0} : Can''t get forks. {1}", new Object[]{repository.getFullName(), ex.getMessage()}); // NOI18N
}
}
return forks;
}
/**
* Get the user for the OAuth Token.
*
* @param oAuthToken OAuth token
* @return User if it can be got, otherwise {@code null}
*/
@CheckForNull
public static synchronized User getUser(String oAuthToken) {
if (StringUtils.isEmpty(oAuthToken)) {
return null;
}
User user = USERS.get(oAuthToken);
if (user == null) {
GitHubClient client = new GitHubClient().setOAuth2Token(oAuthToken);
UserService userService = new UserService(client);
try {
user = userService.getUser();
if (user != null) {
USERS.put(oAuthToken, user);
}
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "Can''t get user. {0}", ex.getMessage()); // NOI18N
}
}
return user;
}
}