James Moger
2011-10-21 b75734f0600c333d70a3659af82be54caf3cfd3e
Revised settings RPC to be Map<String, SettingModel>.

Added setting metadata. Added server status rpc. Improved setting tab in
Manager.
4 files added
11 files modified
695 ■■■■ changed files
build.xml 8 ●●●● patch | view | raw | blame | history
docs/02_rpc.mkd 34 ●●●●● patch | view | raw | blame | history
src/com/gitblit/Constants.java 3 ●●●● patch | view | raw | blame | history
src/com/gitblit/GitBlit.java 103 ●●●●● patch | view | raw | blame | history
src/com/gitblit/RpcServlet.java 14 ●●●● patch | view | raw | blame | history
src/com/gitblit/client/EditUserDialog.java 13 ●●●● patch | view | raw | blame | history
src/com/gitblit/client/GitblitModel.java 17 ●●●● patch | view | raw | blame | history
src/com/gitblit/client/GitblitPanel.java 13 ●●●●● patch | view | raw | blame | history
src/com/gitblit/client/SettingCellRenderer.java 67 ●●●●● patch | view | raw | blame | history
src/com/gitblit/client/SettingPanel.java 114 ●●●●● patch | view | raw | blame | history
src/com/gitblit/client/SettingsModel.java 24 ●●●● patch | view | raw | blame | history
src/com/gitblit/models/ServerStatus.java 69 ●●●●● patch | view | raw | blame | history
src/com/gitblit/models/SettingModel.java 144 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/RpcUtils.java 60 ●●●●● patch | view | raw | blame | history
tests/com/gitblit/tests/RpcTests.java 12 ●●●● patch | view | raw | blame | history
build.xml
@@ -104,6 +104,11 @@
            </fileset>
        </copy>
        <!-- copy gitblit.properties to the WEB-INF folder.
             this file is only used for parsing setting descriptions. -->
        <copy todir="${basedir}/src/WEB-INF" overwrite="true"
            file="${basedir}/distrib/gitblit.properties" />
        <!-- Compile the build tool and execute it.
             This downloads missing compile-time dependencies from Maven. -->
@@ -306,10 +311,11 @@
        
        <delete dir="${project.war.dir}" />        
        <!-- Copy web.xml and users.properties to WEB-INF -->
        <!-- Copy web.xml, users.properties, and gitblit.properties to WEB-INF -->
        <copy todir="${project.war.dir}/WEB-INF">
            <fileset dir="${basedir}/distrib">
                 <include name="users.properties" />
                <include name="gitblit.properties" />
            </fileset>
            <fileset dir="${basedir}/src/WEB-INF">
                 <include name="web.xml" />
docs/02_rpc.mkd
@@ -30,10 +30,10 @@
<tr><td>LIST_FEDERATION_RESULTS</td><td>-</td><td><em>admin</em></td><td>-</td><td>List&lt;FederationModel&gt;</td></tr>
<tr><td>LIST_FEDERATION_PROPOSALS</td><td>-</td><td><em>admin</em></td><td>-</td><td>List&lt;FederationProposal&gt;</td></tr>
<tr><td>LIST_FEDERATION_SETS</td><td>-</td><td><em>admin</em></td><td>-</td><td>List&lt;FederationSet&gt;</td></tr>
<tr><td>LIST_SETTINGS</td><td>-</td><td><em>admin</em></td><td>-</td><td>Properties</td></tr>
<tr><td>LIST_SETTINGS</td><td>-</td><td><em>admin</em></td><td>-</td><td>Map&lt;String, SettingModel&gt;</td></tr>
</table>
### RPC Response Codes
### RPC/HTTP Response Codes
<table>
<tr><th>code</th><th>name</th><th>description</th></tr>
<tr><td>200</td><td>success</td><td>Gitblit processed the request successfully</td></tr>
@@ -47,7 +47,7 @@
### Gitblit Manager
[Gitblit Manager](http://code.google.com/p/gitblit/downloads/detail?name=%MANAGER%) is an example Java/Swing application that allows remote administration of a Gitblit server.  
This application exercises most methods from the utility class `com.gitblit.utils.RpcUtils`.
This application exercises many, but not all, methods from the utility class `com.gitblit.utils.RpcUtils`.
### EGit "Import from Gitblit" Feature (Planning)
@@ -153,4 +153,32 @@
    ]
  }
]
</pre>
### Example: LIST_SETTINGS
**url**: https://localhost/rpc?req=LIST_SETTINGS
**response body**: Map&lt;String, SettingModel&gt;
<pre>
{
  "web.siteName": {
    "name": "web.siteName",
    "currentValue": "",
    "defaultValue": "",
    "description": "Gitblit Web Settings\nIf blank Gitblit is displayed.",
    "since": "0.5.0",
    "caseSensitive": false,
    "restartRequired": false,
    "spaceDelimited": false
  },
  "web.summaryCommitCount": {
    "name": "web.summaryCommitCount",
    "currentValue": "16",
    "defaultValue": "16",
    "description": "The number of commits to display on the summary page\nValue must exceed 0 else default of 16 is used",
    "since": "0.5.0",
    "caseSensitive": false,
    "restartRequired": false,
    "spaceDelimited": false
  }
}
</pre>
src/com/gitblit/Constants.java
@@ -204,7 +204,8 @@
        LIST_REPOSITORIES, CREATE_REPOSITORY, EDIT_REPOSITORY, DELETE_REPOSITORY,
        LIST_USERS, CREATE_USER, EDIT_USER, DELETE_USER, LIST_REPOSITORY_MEMBERS,
        SET_REPOSITORY_MEMBERS, LIST_FEDERATION_REGISTRATIONS, LIST_FEDERATION_RESULTS,
        LIST_FEDERATION_PROPOSALS, LIST_FEDERATION_SETS, LIST_SETTINGS;
        LIST_FEDERATION_PROPOSALS, LIST_FEDERATION_SETS, LIST_SETTINGS,
        LIST_SERVER_STATUS;
        public static RpcRequest fromName(String name) {
            for (RpcRequest type : values()) {
src/com/gitblit/GitBlit.java
@@ -15,9 +15,12 @@
 */
package com.gitblit;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -27,6 +30,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -35,6 +39,7 @@
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.Cookie;
@@ -63,6 +68,8 @@
import com.gitblit.models.Metric;
import com.gitblit.models.ObjectCache;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ByteFormat;
import com.gitblit.utils.FederationUtils;
@@ -106,6 +113,8 @@
    private RepositoryResolver<Void> repositoryResolver;
    private ServletContext servletContext;
    private File repositoriesFolder;
    private boolean exportAll = true;
@@ -113,6 +122,10 @@
    private IUserService userService;
    private IStoredSettings settings;
    private Map<String, SettingModel> settingModels;
    private ServerStatus serverStatus;
    private MailExecutor mailExecutor;
@@ -231,6 +244,13 @@
     */
    public static boolean isDebugMode() {
        return self().settings.getBoolean(Keys.web.debugMode, false);
    }
    public ServerStatus getStatus() {
        // update heap memory status
        serverStatus.heapAllocated = Runtime.getRuntime().totalMemory();
        serverStatus.heapFree = Runtime.getRuntime().freeMemory();
        return serverStatus;
    }
    /**
@@ -1253,6 +1273,86 @@
    }
    /**
     * Returns the descriptions/comments of the Gitblit config settings.
     *
     * @return Map<String, SettingModel>
     */
    public Map<String, SettingModel> getSettingModels() {
        // ensure that the current values are updated in the setting models
        for (String key : settings.getAllKeys(null)) {
            if (settingModels.containsKey(key)) {
                settingModels.get(key).currentValue = settings.getString(key, "");
            }
        }
        return settingModels;
    }
    /**
     * Parse the properties file and aggregate all the comments by the setting
     * key. A setting model tracks the current value, the default value, the
     * description of the setting and and directives about the setting.
     *
     * @return Map<String, SettingModel>
     */
    private Map<String, SettingModel> loadSettingModels() {
        Map<String, SettingModel> map = new TreeMap<String, SettingModel>();
        try {
            // Read bundled Gitblit properties to extract setting descriptions.
            // This copy is pristine and only used for populating the setting
            // models map.
            InputStream is = servletContext.getResourceAsStream("/WEB-INF/gitblit.properties");
            BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is));
            StringBuilder description = new StringBuilder();
            SettingModel setting = new SettingModel();
            String line = null;
            while ((line = propertiesReader.readLine()) != null) {
                if (line.length() == 0) {
                    description.setLength(0);
                    setting = new SettingModel();
                } else {
                    if (line.charAt(0) == '#') {
                        if (line.length() > 1) {
                            String text = line.substring(1).trim();
                            if (SettingModel.CASE_SENSITIVE.equals(text)) {
                                setting.caseSensitive = true;
                            } else if (SettingModel.RESTART_REQUIRED.equals(text)) {
                                setting.restartRequired = true;
                            } else if (SettingModel.SPACE_DELIMITED.equals(text)) {
                                setting.spaceDelimited = true;
                            } else if (text.startsWith(SettingModel.SINCE)) {
                                try {
                                    setting.since = text.split(" ")[1];
                                } catch (Exception e) {
                                    setting.since = text;
                                }
                            } else {
                                description.append(text);
                                description.append('\n');
                            }
                        }
                    } else {
                        String[] kvp = line.split("=", 2);
                        String key = kvp[0].trim();
                        setting.name = key;
                        setting.defaultValue = kvp[1].trim();
                        setting.currentValue = setting.defaultValue;
                        setting.description = description.toString().trim();
                        map.put(key, setting);
                        description.setLength(0);
                        setting = new SettingModel();
                    }
                }
            }
            propertiesReader.close();
        } catch (NullPointerException e) {
            logger.error("Failed to find resource copy of gitblit.properties");
        } catch (IOException e) {
            logger.error("Failed to load resource copy of gitblit.properties");
        }
        return map;
    }
    /**
     * Configure the Gitblit singleton with the specified settings source. This
     * source may be file settings (Gitblit GO) or may be web.xml settings
     * (Gitblit WAR).
@@ -1265,6 +1365,7 @@
        repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "git"));
        logger.info("Git repositories folder " + repositoriesFolder.getAbsolutePath());
        repositoryResolver = new FileResolver<Void>(repositoriesFolder, exportAll);
        serverStatus = new ServerStatus();
        String realm = settings.getString(Keys.realm.userService, "users.properties");
        IUserService loginService = null;
        try {
@@ -1307,6 +1408,8 @@
     */
    @Override
    public void contextInitialized(ServletContextEvent contextEvent) {
        servletContext = contextEvent.getServletContext();
        settingModels = loadSettingModels();
        if (settings == null) {
            // Gitblit WAR is running in a servlet container
            WebXmlSettings webxmlSettings = new WebXmlSettings(contextEvent.getServletContext());
src/com/gitblit/RpcServlet.java
@@ -22,7 +22,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -183,15 +182,10 @@
            }
        } else if (RpcRequest.LIST_SETTINGS.equals(reqType)) {
            // return the server's settings
            Properties settings = new Properties();
            List<String> keys = GitBlit.getAllKeys(null);
            for (String key : keys) {
                String value = GitBlit.getString(key, null);
                if (value != null) {
                    settings.put(key, value);
                }
            }
            result = settings;
            result = GitBlit.self().getSettingModels();
        } else if (RpcRequest.LIST_SERVER_STATUS.equals(reqType)) {
            // return the server's status information
            result = GitBlit.self().getStatus();
        }
        // send the result of the request
src/com/gitblit/client/EditUserDialog.java
@@ -29,6 +29,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.ImageIcon;
@@ -45,9 +46,9 @@
import javax.swing.KeyStroke;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.SettingModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
@@ -57,7 +58,7 @@
    private final UserModel user;
    private final IStoredSettings settings;
    private final Map<String, SettingModel> settings;
    private boolean isCreate;
    
@@ -77,13 +78,13 @@
    private Set<String> usernames;
    public EditUserDialog(IStoredSettings settings) {
    public EditUserDialog(Map<String, SettingModel> settings) {
        this(new UserModel(""), settings);
        this.isCreate = true;
        setTitle(Translation.get("gb.newUser"));        
    }
    public EditUserDialog(UserModel anUser, IStoredSettings settings) {
    public EditUserDialog(UserModel anUser, Map<String, SettingModel> settings) {
        super();
        this.user = new UserModel("");
        this.settings = settings;
@@ -196,7 +197,7 @@
            }
        }
        int minLength = settings.getInteger(Keys.realm.minPasswordLength, 5);
        int minLength = settings.get(Keys.realm.minPasswordLength).getInteger(5);
        if (minLength < 4) {
            minLength = 4;
        }
@@ -216,7 +217,7 @@
            return false;
        }
        user.username = uname;
        String type = settings.getString(Keys.realm.passwordStorage, "md5");
        String type = settings.get(Keys.realm.passwordStorage).getString("md5");
        if (type.equalsIgnoreCase("md5")) {
            // store MD5 digest of password
            user.password = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(pw));
src/com/gitblit/client/GitblitModel.java
@@ -24,10 +24,11 @@
import com.gitblit.GitBlitException.ForbiddenException;
import com.gitblit.GitBlitException.UnauthorizedException;
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.models.FederationModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.RpcUtils;
@@ -43,13 +44,15 @@
    private volatile boolean isAdmin;
    private volatile IStoredSettings settings;
    private volatile Map<String, SettingModel> settings;
    private final List<RepositoryModel> allRepositories;
    private final List<UserModel> allUsers;
    private final List<FederationModel> federationRegistrations;
    private ServerStatus status;
    public GitblitModel(String url, String account, char[] password) {
        this.url = url;
@@ -66,8 +69,8 @@
        try {
            settings = RpcUtils.getSettings(url, account, password);
            status = RpcUtils.getStatus(url, account, password);
            refreshUsers();
            refreshFederationRegistrations();
            isAdmin = true;
        } catch (UnauthorizedException e) {
        } catch (ForbiddenException e) {
@@ -84,8 +87,12 @@
        return account != null && account.equalsIgnoreCase(model.owner);
    }
    public IStoredSettings getSettings() {
    public Map<String, SettingModel> getSettings() {
        return settings;
    }
    public String getSettingDescription(String key) {
        return settings.get(key).description;
    }
    public List<RepositoryModel> refreshRepositories() throws IOException {
@@ -135,7 +142,7 @@
    }
    public List<String> getFederationSets() {
        return settings.getStrings(Keys.federation.sets);
        return settings.get(Keys.federation.sets).getStrings();
    }
    public List<RepositoryModel> getRepositories() {
src/com/gitblit/client/GitblitPanel.java
@@ -52,6 +52,7 @@
import com.gitblit.Constants.RpcRequest;
import com.gitblit.client.ClosableTabComponent.CloseTabListener;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.SettingModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
@@ -116,7 +117,6 @@
        tabs = new JTabbedPane(JTabbedPane.BOTTOM);
        tabs.addTab(Translation.get("gb.repositories"), createRepositoriesPanel());
        tabs.addTab(Translation.get("gb.users"), createUsersPanel());
        tabs.addTab(Translation.get("gb.federation"), new JPanel());
        tabs.addTab(Translation.get("gb.settings"), createSettingsPanel());
        setLayout(new BorderLayout());
@@ -380,9 +380,11 @@
    }
    private JPanel createSettingsPanel() {
        final SettingPanel settingPanel = new SettingPanel();
        settingsModel = new SettingsModel();
        defaultSettingsSorter = new TableRowSorter<SettingsModel>(settingsModel);
        settingsTable = Utils.newTable(settingsModel);
        settingsTable.setDefaultRenderer(SettingModel.class, new SettingCellRenderer());
        String name = settingsTable.getColumnName(UsersModel.Columns.Name.ordinal());
        settingsTable.setRowHeight(nameRenderer.getFont().getSize() + 8);
        settingsTable.getColumn(name).setCellRenderer(nameRenderer);
@@ -398,6 +400,14 @@
                boolean selected = settingsTable.getSelectedRow() > -1;
                boolean singleSelection = settingsTable.getSelectedRows().length == 1;
                // TODO enable/disable setting buttons
                if (singleSelection) {
                    int viewRow = settingsTable.getSelectedRow();
                    int modelRow = settingsTable.convertRowIndexToModel(viewRow);
                    SettingModel setting = settingsModel.get(modelRow);
                    settingPanel.setSetting(setting);
                } else {
                    settingPanel.clear();
                }
            }
        });
@@ -420,6 +430,7 @@
        JPanel settingsTablePanel = new JPanel(new BorderLayout(margin, margin));
        settingsTablePanel.add(settingFilterPanel, BorderLayout.NORTH);
        settingsTablePanel.add(new JScrollPane(settingsTable), BorderLayout.CENTER);
        settingsTablePanel.add(settingPanel, BorderLayout.SOUTH);
        JPanel settingsControls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
        // TODO update setting?
src/com/gitblit/client/SettingCellRenderer.java
New file
@@ -0,0 +1,67 @@
/*
 * 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.Color;
import java.awt.Component;
import java.awt.Font;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import com.gitblit.models.SettingModel;
/**
 * SettingModel cell renderer that indicates if a setting is the default or
 * modified.
 *
 * @author James Moger
 *
 */
public class SettingCellRenderer extends DefaultTableCellRenderer {
    private static final long serialVersionUID = 1L;
    private final Font defaultFont;
    private final Font modifiedFont;
    public SettingCellRenderer() {
        defaultFont = getFont();
        modifiedFont = defaultFont.deriveFont(Font.BOLD);
    }
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
            boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        if (value instanceof SettingModel) {
            SettingModel setting = (SettingModel) value;
            if (setting.isDefaultValue()) {
                this.setFont(defaultFont);
                if (!isSelected) {
                    this.setForeground(Color.BLACK);
                }
            } else {
                this.setFont(modifiedFont);
                if (!isSelected) {
                    this.setForeground(Color.BLUE);
                }
            }
            this.setText(setting.getString(""));
        }
        return this;
    }
}
src/com/gitblit/client/SettingPanel.java
New file
@@ -0,0 +1,114 @@
/*
 * 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.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import com.gitblit.models.SettingModel;
import com.gitblit.utils.StringUtils;
/**
 * This panel displays the metadata for a particular setting.
 *
 * @author James Moger
 */
public class SettingPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    private JTextArea descriptionArea;
    private JLabel settingName;
    private JLabel settingDefault;
    private JLabel sinceVersion;
    private JLabel directives;
    public SettingPanel() {
        super();
        initialize();
    }
    private void initialize() {
        descriptionArea = new JTextArea();
        descriptionArea.setRows(6);
        descriptionArea.setFont(new Font("monospaced", Font.PLAIN, 11));
        settingName = new JLabel(" ");
        settingName.setFont(settingName.getFont().deriveFont(Font.BOLD));
        settingDefault = new JLabel(" ");
        sinceVersion = new JLabel(" ", SwingConstants.RIGHT);
        sinceVersion.setForeground(new Color(0, 0x80, 0));
        directives = new JLabel(" ", SwingConstants.RIGHT);
        directives.setFont(directives.getFont().deriveFont(Font.ITALIC));
        JPanel settingParameters = new JPanel(new GridLayout(2, 2, 0, 0));
        settingParameters.add(settingName);
        settingParameters.add(sinceVersion);
        settingParameters.add(settingDefault, BorderLayout.CENTER);
        settingParameters.add(directives);
        JPanel settingPanel = new JPanel(new BorderLayout(5, 5));
        settingPanel.add(settingParameters, BorderLayout.NORTH);
        settingPanel.add(new JScrollPane(descriptionArea), BorderLayout.CENTER);
        setLayout(new BorderLayout(0, 0));
        add(settingPanel, BorderLayout.CENTER);
    }
    public void setSetting(SettingModel setting) {
        settingName.setText(setting.name);
        if (setting.since == null) {
            sinceVersion.setText("custom");
        } else {
            sinceVersion.setText("since " + setting.since);
        }
        settingDefault.setText("default: " + setting.defaultValue);
        List<String> values = new ArrayList<String>();
        if (setting.caseSensitive) {
            values.add("CASE-SENSITIVE");
        }
        if (setting.spaceDelimited) {
            values.add("SPACE-DELIMITED");
        }
        if (setting.restartRequired) {
            values.add("RESTART REQUIRED");
        }
        directives.setText(StringUtils.flattenStrings(values, ", "));
        descriptionArea.setText(setting.description);
        descriptionArea.setCaretPosition(0);
    }
    public void clear() {
        settingName.setText(" ");
        settingDefault.setText(" ");
        sinceVersion.setText(" ");
        directives.setText(" ");
        descriptionArea.setText("");
    }
}
src/com/gitblit/client/SettingsModel.java
@@ -18,13 +18,14 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.swing.table.AbstractTableModel;
import com.gitblit.IStoredSettings;
import com.gitblit.models.SettingModel;
/**
 * Table model of IStoredSettings.
 * Table model of Map<String, SettingModel>.
 * 
 * @author James Moger
 * 
@@ -33,7 +34,7 @@
    private static final long serialVersionUID = 1L;
    IStoredSettings settings;
    Map<String, SettingModel> settings;
    List<String> keys;
@@ -50,16 +51,16 @@
        this(null);
    }
    public SettingsModel(IStoredSettings settings) {
    public SettingsModel(Map<String, SettingModel> settings) {
        setSettings(settings);
    }
    public void setSettings(IStoredSettings settings) {
    public void setSettings(Map<String, SettingModel> settings) {
        this.settings = settings;
        if (settings == null) {
            keys = new ArrayList<String>();
        } else {
            keys = new ArrayList<String>(settings.getAllKeys(null));
            keys = new ArrayList<String>(settings.keySet());
            Collections.sort(keys);
        }
    }
@@ -92,19 +93,28 @@
     * @return the Object.class
     */
    public Class<?> getColumnClass(int columnIndex) {
        if (Columns.Value.ordinal() == columnIndex) {
            return SettingModel.class;
        }
        return String.class;
    }
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        String key = keys.get(rowIndex);
        SettingModel setting = settings.get(key);
        Columns col = Columns.values()[columnIndex];
        switch (col) {
        case Name:
            return key;
        case Value:
            return settings.getString(key, "");
            return setting;
        }
        return null;
    }
    public SettingModel get(int modelRow) {
        String key = keys.get(modelRow);
        return settings.get(key);
    }
}
src/com/gitblit/models/ServerStatus.java
New file
@@ -0,0 +1,69 @@
/*
 * 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.models;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * ServerStatus encapsulates runtime status information about the server
 * including the system environment.
 *
 * @author James Moger
 *
 */
public class ServerStatus implements Serializable {
    private static final long serialVersionUID = 1L;
    public final Date bootDate;
    public final long heapSize;
    public final Map<String, String> systemProperties;
    public volatile long heapAllocated;
    public volatile long heapFree;
    public ServerStatus() {
        bootDate = new Date();
        heapSize = Runtime.getRuntime().maxMemory();
        systemProperties = new HashMap<String, String>();
        put("file.encoding");
        put("java.home");
        put("java.io.tmpdir");
        put("java.runtime.name");
        put("java.runtime.version");
        put("java.vendor");
        put("java.version");
        put("java.vm.info");
        put("java.vm.name");
        put("java.vm.vendor");
        put("java.vm.version");
        put("os.arch");
        put("os.name");
        put("os.version");
    }
    private void put(String key) {
        systemProperties.put(key, System.getProperty(key));
    }
}
src/com/gitblit/models/SettingModel.java
New file
@@ -0,0 +1,144 @@
/*
 * 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.models;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.gitblit.utils.StringUtils;
/**
 * SettingModel represents a setting and all its metadata: name, current value,
 * default value, description, and directives.
 *
 * @author James Moger
 */
public class SettingModel implements Serializable {
    public static final String SPACE_DELIMITED = "SPACE-DELIMITED";
    public static final String CASE_SENSITIVE = "CASE-SENSITIVE";
    public static final String RESTART_REQUIRED = "RESTART REQUIRED";
    public static final String SINCE = "SINCE";
    public String name;
    public volatile String currentValue;
    public String defaultValue;
    public String description;
    public String since;
    public boolean caseSensitive;
    public boolean restartRequired;
    public boolean spaceDelimited;
    private static final long serialVersionUID = 1L;
    public SettingModel() {
    }
    /**
     * Returns true if the current value is the default value.
     *
     * @return true if current value is the default value
     */
    public boolean isDefaultValue() {
        return (currentValue != null && currentValue.equals(defaultValue))
                || currentValue.trim().length() == 0;
    }
    /**
     * Returns the boolean value for the currentValue. If the currentValue can
     * not be interpreted as a boolean, the defaultValue is returned.
     *
     * @param defaultValue
     * @return key value or defaultValue
     */
    public boolean getBoolean(boolean defaultValue) {
        if (!StringUtils.isEmpty(currentValue)) {
            return Boolean.parseBoolean(currentValue.trim());
        }
        return defaultValue;
    }
    /**
     * Returns the integer value for the currentValue. If the currentValue can
     * not be interpreted as an integer, the defaultValue is returned.
     *
     * @param defaultValue
     * @return key value or defaultValue
     */
    public int getInteger(int defaultValue) {
        try {
            if (!StringUtils.isEmpty(currentValue)) {
                return Integer.parseInt(currentValue.trim());
            }
        } catch (NumberFormatException e) {
        }
        return defaultValue;
    }
    /**
     * Returns the char value for currentValue. If the currentValue can not be
     * interpreted as a char, the defaultValue is returned.
     *
     * @param defaultValue
     * @return key value or defaultValue
     */
    public char getChar(char defaultValue) {
        if (!StringUtils.isEmpty(currentValue)) {
            return currentValue.trim().charAt(0);
        }
        return defaultValue;
    }
    /**
     * Returns the string value for currentValue. If the currentValue is null,
     * the defaultValue is returned.
     *
     * @param defaultValue
     * @return key value or defaultValue
     */
    public String getString(String defaultValue) {
        if (currentValue != null) {
            return currentValue.trim();
        }
        return defaultValue;
    }
    /**
     * Returns a list of space-separated strings from the specified key.
     *
     * @return list of strings
     */
    public List<String> getStrings() {
        return getStrings(" ");
    }
    /**
     * Returns a list of strings from the currentValue using the specified
     * string separator.
     *
     * @param separator
     * @return list of strings
     */
    public List<String> getStrings(String separator) {
        List<String> strings = new ArrayList<String>();
        strings = StringUtils.getStringsFromValue(currentValue, separator);
        return strings;
    }
}
src/com/gitblit/utils/RpcUtils.java
@@ -21,15 +21,15 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.gitblit.Constants;
import com.gitblit.Constants.RpcRequest;
import com.gitblit.IStoredSettings;
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.gitblit.models.UserModel;
import com.google.gson.reflect.TypeToken;
@@ -57,6 +57,9 @@
    }.getType();
    private static final Type SETS_TYPE = new TypeToken<Collection<FederationSet>>() {
    }.getType();
    private static final Type SETTINGS_TYPE = new TypeToken<Map<String, SettingModel>>() {
    }.getType();
    /**
@@ -338,15 +341,31 @@
     * @param serverUrl
     * @param account
     * @param password
     * @return an IStoredSettings object
     * @return an Map<String, SettingModel> object
     * @throws IOException
     */
    public static IStoredSettings getSettings(String serverUrl, String account, char[] password)
            throws IOException {
    public static Map<String, SettingModel> getSettings(String serverUrl, String account,
            char[] password) throws IOException {
        String url = asLink(serverUrl, RpcRequest.LIST_SETTINGS);
        Properties props = JsonUtils.retrieveJson(url, Properties.class, account, password);
        RpcSettings settings = new RpcSettings(props);
        Map<String, SettingModel> settings = JsonUtils.retrieveJson(url, SETTINGS_TYPE, account,
                password);
        return settings;
    }
    /**
     * Retrieves the server status object.
     *
     * @param serverUrl
     * @param account
     * @param password
     * @return an ServerStatus object
     * @throws IOException
     */
    public static ServerStatus getStatus(String serverUrl, String account, char[] password)
            throws IOException {
        String url = asLink(serverUrl, RpcRequest.LIST_SERVER_STATUS);
        ServerStatus status = JsonUtils.retrieveJson(url, ServerStatus.class, account, password);
        return status;
    }
    /**
@@ -368,32 +387,5 @@
        String json = JsonUtils.toJsonString(object);
        int resultCode = JsonUtils.sendJsonString(url, json, account, password);
        return resultCode == 200;
    }
    /**
     * Settings implementation that wraps a retrieved properties instance. This
     * class is used for RPC communication.
     *
     * @author James Moger
     *
     */
    private static class RpcSettings extends IStoredSettings {
        private final Properties properties = new Properties();
        public RpcSettings(Properties props) {
            super(RpcSettings.class);
            properties.putAll(props);
        }
        @Override
        protected Properties read() {
            return properties;
        }
        @Override
        public String toString() {
            return "RpcSettings";
        }
    }
}
tests/com/gitblit/tests/RpcTests.java
@@ -23,11 +23,12 @@
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlitException.UnauthorizedException;
import com.gitblit.IStoredSettings;
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.RpcUtils;
@@ -206,7 +207,12 @@
    }
    public void testSettings() throws Exception {
        IStoredSettings settings = RpcUtils.getSettings(url, account, password.toCharArray());
        assertTrue("No settings were retrieved!", settings.getAllKeys(null).size() > 0);
        Map<String, SettingModel> settings = RpcUtils.getSettings(url, account, password.toCharArray());
        assertTrue("No settings were retrieved!", settings != null);
    }
    public void testServerStatus() throws Exception {
        ServerStatus status = RpcUtils.getStatus(url, account, password.toCharArray());
        assertTrue("No status was retrieved!", status != null);
    }
}