/* | |
* Copyright 2011 gitblit.com. | |
* | |
* 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 com.gitblit.client; | |
import java.awt.BorderLayout; | |
import java.awt.Cursor; | |
import java.awt.Dimension; | |
import java.awt.EventQueue; | |
import java.awt.Point; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.awt.event.KeyEvent; | |
import java.awt.event.WindowAdapter; | |
import java.awt.event.WindowEvent; | |
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.net.ConnectException; | |
import java.text.MessageFormat; | |
import java.text.SimpleDateFormat; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.Date; | |
import java.util.HashMap; | |
import java.util.LinkedHashMap; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.TimeZone; | |
import javax.swing.ImageIcon; | |
import javax.swing.JFrame; | |
import javax.swing.JMenu; | |
import javax.swing.JMenuBar; | |
import javax.swing.JMenuItem; | |
import javax.swing.JOptionPane; | |
import javax.swing.JPanel; | |
import javax.swing.JTabbedPane; | |
import javax.swing.KeyStroke; | |
import javax.swing.SwingWorker; | |
import javax.swing.UIManager; | |
import org.eclipse.jgit.errors.ConfigInvalidException; | |
import org.eclipse.jgit.lib.StoredConfig; | |
import org.eclipse.jgit.storage.file.FileBasedConfig; | |
import org.eclipse.jgit.util.FS; | |
import com.gitblit.Constants; | |
import com.gitblit.GitBlitException.ForbiddenException; | |
import com.gitblit.models.FeedModel; | |
import com.gitblit.utils.Base64; | |
import com.gitblit.utils.StringUtils; | |
/** | |
* Gitblit Manager issues JSON RPC requests to a Gitblit server. | |
* | |
* @author James Moger | |
* | |
*/ | |
public class GitblitManager extends JFrame implements RegistrationsDialog.RegistrationListener { | |
private static final long serialVersionUID = 1L; | |
private static final String SERVER = "server"; | |
private static final String FEED = "feed"; | |
private final SimpleDateFormat dateFormat; | |
private JTabbedPane serverTabs; | |
private File configFile = new File(System.getProperty("user.home"), ".gitblit/config"); | |
private Map<String, GitblitRegistration> registrations = new LinkedHashMap<String, GitblitRegistration>(); | |
private JMenu recentMenu; | |
private int maxRecentCount = 5; | |
private GitblitManager() { | |
super(); | |
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); | |
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); | |
} | |
private void initialize() { | |
setContentPane(getCenterPanel()); | |
setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage()); | |
setTitle("Gitblit Manager v" + Constants.getVersion() + " (" + Constants.getBuildDate() + ")"); | |
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
addWindowListener(new WindowAdapter() { | |
@Override | |
public void windowClosing(WindowEvent event) { | |
saveSizeAndPosition(); | |
} | |
@Override | |
public void windowOpened(WindowEvent event) { | |
manageRegistrations(); | |
} | |
}); | |
setSizeAndPosition(); | |
loadRegistrations(); | |
rebuildRecentMenu(); | |
} | |
private void setSizeAndPosition() { | |
String sz = null; | |
String pos = null; | |
try { | |
StoredConfig config = getConfig(); | |
sz = config.getString("ui", null, "size"); | |
pos = config.getString("ui", null, "position"); | |
} catch (Throwable t) { | |
t.printStackTrace(); | |
} | |
// try to restore saved window size | |
if (StringUtils.isEmpty(sz)) { | |
setSize(850, 500); | |
} else { | |
String[] chunks = sz.split("x"); | |
int width = Integer.parseInt(chunks[0]); | |
int height = Integer.parseInt(chunks[1]); | |
setSize(width, height); | |
} | |
// try to restore saved window position | |
if (StringUtils.isEmpty(pos)) { | |
setLocationRelativeTo(null); | |
} else { | |
String[] chunks = pos.split(","); | |
int x = Integer.parseInt(chunks[0]); | |
int y = Integer.parseInt(chunks[1]); | |
setLocation(x, y); | |
} | |
} | |
private void saveSizeAndPosition() { | |
try { | |
// save window size and position | |
StoredConfig config = getConfig(); | |
Dimension sz = GitblitManager.this.getSize(); | |
config.setString("ui", null, "size", | |
MessageFormat.format("{0,number,0}x{1,number,0}", sz.width, sz.height)); | |
Point pos = GitblitManager.this.getLocationOnScreen(); | |
config.setString("ui", null, "position", | |
MessageFormat.format("{0,number,0},{1,number,0}", pos.x, pos.y)); | |
config.save(); | |
} catch (Throwable t) { | |
Utils.showException(GitblitManager.this, t); | |
} | |
} | |
private JMenuBar setupMenu() { | |
JMenuBar menuBar = new JMenuBar(); | |
JMenu serversMenu = new JMenu(Translation.get("gb.servers")); | |
menuBar.add(serversMenu); | |
recentMenu = new JMenu(Translation.get("gb.recent")); | |
serversMenu.add(recentMenu); | |
JMenuItem manage = new JMenuItem(Translation.get("gb.manage") + "..."); | |
manage.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK, false)); | |
manage.addActionListener(new ActionListener() { | |
@Override | |
public void actionPerformed(ActionEvent event) { | |
manageRegistrations(); | |
} | |
}); | |
serversMenu.add(manage); | |
return menuBar; | |
} | |
private JPanel getCenterPanel() { | |
serverTabs = new JTabbedPane(JTabbedPane.TOP); | |
JMenuBar menubar = setupMenu(); | |
JPanel panel = new JPanel(new BorderLayout()); | |
panel.add(menubar, BorderLayout.NORTH); | |
panel.add(serverTabs, BorderLayout.CENTER); | |
return panel; | |
} | |
private void manageRegistrations() { | |
RegistrationsDialog dialog = new RegistrationsDialog(new ArrayList<GitblitRegistration>( | |
registrations.values()), this); | |
dialog.setLocationRelativeTo(GitblitManager.this); | |
dialog.setVisible(true); | |
} | |
@Override | |
public void login(GitblitRegistration reg) { | |
if (!reg.savePassword && (reg.password == null || reg.password.length == 0)) { | |
// prompt for password | |
EditRegistrationDialog dialog = new EditRegistrationDialog(this, reg, true); | |
dialog.setLocationRelativeTo(GitblitManager.this); | |
dialog.setVisible(true); | |
GitblitRegistration newReg = dialog.getRegistration(); | |
if (newReg == null) { | |
// user canceled | |
return; | |
} | |
// preserve feeds | |
newReg.feeds.addAll(reg.feeds); | |
// use new reg | |
reg = newReg; | |
} | |
// login | |
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); | |
final GitblitRegistration registration = reg; | |
final GitblitPanel panel = new GitblitPanel(registration, this); | |
SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() { | |
@Override | |
protected Boolean doInBackground() throws IOException { | |
panel.login(); | |
return true; | |
} | |
@Override | |
protected void done() { | |
try { | |
boolean success = get(); | |
serverTabs.addTab(registration.name, panel); | |
int idx = serverTabs.getTabCount() - 1; | |
serverTabs.setSelectedIndex(idx); | |
serverTabs.setTabComponentAt(idx, new ClosableTabComponent(registration.name, | |
null, serverTabs, panel)); | |
registration.lastLogin = new Date(); | |
saveRegistration(registration.name, registration); | |
registrations.put(registration.name, registration); | |
rebuildRecentMenu(); | |
if (!registration.savePassword) { | |
// clear password | |
registration.password = null; | |
} | |
} catch (Throwable t) { | |
Throwable cause = t.getCause(); | |
if (cause instanceof ConnectException) { | |
JOptionPane.showMessageDialog(GitblitManager.this, cause.getMessage(), | |
Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE); | |
} else if (cause instanceof ForbiddenException) { | |
JOptionPane | |
.showMessageDialog( | |
GitblitManager.this, | |
"This Gitblit server does not allow RPC Management or Administration", | |
Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE); | |
} else { | |
Utils.showException(GitblitManager.this, t); | |
} | |
} finally { | |
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); | |
} | |
} | |
}; | |
worker.execute(); | |
} | |
private void rebuildRecentMenu() { | |
recentMenu.removeAll(); | |
ImageIcon icon = new ImageIcon(getClass().getResource("/gitblt-favicon.png")); | |
List<GitblitRegistration> list = new ArrayList<GitblitRegistration>(registrations.values()); | |
Collections.sort(list, new Comparator<GitblitRegistration>() { | |
@Override | |
public int compare(GitblitRegistration o1, GitblitRegistration o2) { | |
return o2.lastLogin.compareTo(o1.lastLogin); | |
} | |
}); | |
if (list.size() > maxRecentCount) { | |
list = list.subList(0, maxRecentCount); | |
} | |
for (int i = 0; i < list.size(); i++) { | |
final GitblitRegistration reg = list.get(i); | |
JMenuItem item = new JMenuItem(reg.name, icon); | |
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1 + i, KeyEvent.CTRL_DOWN_MASK, | |
false)); | |
item.addActionListener(new ActionListener() { | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
login(reg); | |
} | |
}); | |
recentMenu.add(item); | |
} | |
} | |
private void loadRegistrations() { | |
try { | |
StoredConfig config = getConfig(); | |
Set<String> servers = config.getSubsections(SERVER); | |
for (String server : servers) { | |
Date lastLogin = new Date(0); | |
String date = config.getString(SERVER, server, "lastLogin"); | |
if (!StringUtils.isEmpty(date)) { | |
lastLogin = dateFormat.parse(date); | |
} | |
String url = config.getString(SERVER, server, "url"); | |
String account = config.getString(SERVER, server, "account"); | |
char[] password; | |
String pw = config.getString(SERVER, server, "password"); | |
if (StringUtils.isEmpty(pw)) { | |
password = new char[0]; | |
} else { | |
password = new String(Base64.decode(pw)).toCharArray(); | |
} | |
GitblitRegistration reg = new GitblitRegistration(server, url, account, password) { | |
private static final long serialVersionUID = 1L; | |
@Override | |
protected void cacheFeeds() { | |
writeFeedCache(this); | |
} | |
}; | |
String[] feeds = config.getStringList(SERVER, server, FEED); | |
if (feeds != null) { | |
// deserialize the field definitions | |
for (String definition : feeds) { | |
FeedModel feed = new FeedModel(definition); | |
reg.feeds.add(feed); | |
} | |
} | |
reg.lastLogin = lastLogin; | |
loadFeedCache(reg); | |
registrations.put(reg.name, reg); | |
} | |
} catch (Throwable t) { | |
Utils.showException(GitblitManager.this, t); | |
} | |
} | |
@Override | |
public boolean saveRegistration(String name, GitblitRegistration reg) { | |
try { | |
StoredConfig config = getConfig(); | |
if (!StringUtils.isEmpty(name) && !name.equals(reg.name)) { | |
// delete old registration | |
registrations.remove(name); | |
config.unsetSection(SERVER, name); | |
} | |
// update registration | |
config.setString(SERVER, reg.name, "url", reg.url); | |
config.setString(SERVER, reg.name, "account", reg.account); | |
if (reg.savePassword) { | |
config.setString(SERVER, reg.name, "password", | |
Base64.encodeBytes(new String(reg.password).getBytes("UTF-8"))); | |
} else { | |
config.setString(SERVER, reg.name, "password", ""); | |
} | |
if (reg.lastLogin != null) { | |
config.setString(SERVER, reg.name, "lastLogin", dateFormat.format(reg.lastLogin)); | |
} | |
// serialize the feed definitions | |
List<String> definitions = new ArrayList<String>(); | |
for (FeedModel feed : reg.feeds) { | |
definitions.add(feed.toString()); | |
} | |
if (definitions.size() > 0) { | |
config.setStringList(SERVER, reg.name, FEED, definitions); | |
} | |
config.save(); | |
return true; | |
} catch (Throwable t) { | |
Utils.showException(GitblitManager.this, t); | |
} | |
return false; | |
} | |
@Override | |
public boolean deleteRegistrations(List<GitblitRegistration> list) { | |
boolean success = false; | |
try { | |
StoredConfig config = getConfig(); | |
for (GitblitRegistration reg : list) { | |
config.unsetSection(SERVER, reg.name); | |
registrations.remove(reg.name); | |
} | |
config.save(); | |
success = true; | |
} catch (Throwable t) { | |
Utils.showException(GitblitManager.this, t); | |
} | |
return success; | |
} | |
private StoredConfig getConfig() throws IOException, ConfigInvalidException { | |
FileBasedConfig config = new FileBasedConfig(configFile, FS.detect()); | |
config.load(); | |
return config; | |
} | |
private void loadFeedCache(GitblitRegistration reg) { | |
File feedCache = new File(configFile.getParentFile(), StringUtils.getSHA1(reg.toString()) | |
+ ".cache"); | |
if (!feedCache.exists()) { | |
// no cache for this registration | |
return; | |
} | |
try { | |
BufferedReader reader = new BufferedReader(new FileReader(feedCache)); | |
Map<String, Date> cache = new HashMap<String, Date>(); | |
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); | |
String line = null; | |
while ((line = reader.readLine()) != null) { | |
String[] kvp = line.split("="); | |
cache.put(kvp[0], df.parse(kvp[1])); | |
} | |
reader.close(); | |
for (FeedModel feed : reg.feeds) { | |
String name = feed.toString(); | |
if (cache.containsKey(name)) { | |
feed.currentRefreshDate = cache.get(name); | |
} | |
} | |
} catch (Exception e) { | |
Utils.showException(GitblitManager.this, e); | |
} | |
} | |
private void writeFeedCache(GitblitRegistration reg) { | |
try { | |
File feedCache = new File(configFile.getParentFile(), StringUtils.getSHA1(reg | |
.toString()) + ".cache"); | |
FileWriter writer = new FileWriter(feedCache); | |
for (FeedModel feed : reg.feeds) { | |
writer.append(MessageFormat.format("{0}={1,date,yyyy-MM-dd'T'HH:mm:ss}\n", | |
feed.toString(), feed.currentRefreshDate)); | |
} | |
writer.close(); | |
} catch (Exception e) { | |
Utils.showException(GitblitManager.this, e); | |
} | |
} | |
public static void main(String[] args) { | |
EventQueue.invokeLater(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | |
} catch (Exception e) { | |
} | |
GitblitManager frame = new GitblitManager(); | |
frame.initialize(); | |
frame.setVisible(true); | |
} | |
}); | |
} | |
} |