Merge branch 'stable-2.8'
* stable-2.8: Bump SSHD version to 0.9.0.201311081 Add REST API to toggle starred change state Change-Id: Ic8d7a1802f6d6319f8f1012f9fe0c7f0c030f60a
This commit is contained in:
@@ -2507,6 +2507,14 @@ namespace. To alias `replication start` to `gerrit replicate`:
|
|||||||
[[sshd]] Section sshd
|
[[sshd]] Section sshd
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
[[sshd.backend]]sshd.backend::
|
||||||
|
+
|
||||||
|
Starting from version 0.9.0 Apache SSHD project added support for NIO2
|
||||||
|
IoSession. To use the new NIO2 session the `backend` option must be set
|
||||||
|
to `NIO2`.
|
||||||
|
+
|
||||||
|
By default, `MINA`.
|
||||||
|
|
||||||
[[sshd.listenAddress]]sshd.listenAddress::
|
[[sshd.listenAddress]]sshd.listenAddress::
|
||||||
+
|
+
|
||||||
Specifies the local addresses the internal SSHD should listen
|
Specifies the local addresses the internal SSHD should listen
|
||||||
@@ -2545,20 +2553,13 @@ of them.
|
|||||||
+
|
+
|
||||||
By default, sshd.listenAddress.
|
By default, sshd.listenAddress.
|
||||||
|
|
||||||
[[sshd.reuseAddress]]sshd.reuseAddress::
|
|
||||||
+
|
|
||||||
If true, permits the daemon to bind to the port even if the port
|
|
||||||
is already in use. If false, the daemon ensures the port is not
|
|
||||||
in use before starting. Busy sites may need to set this to true
|
|
||||||
to permit fast restarts.
|
|
||||||
+
|
|
||||||
By default, true.
|
|
||||||
|
|
||||||
[[sshd.tcpKeepAlive]]sshd.tcpKeepAlive::
|
[[sshd.tcpKeepAlive]]sshd.tcpKeepAlive::
|
||||||
+
|
+
|
||||||
If true, enables TCP keepalive messages to the other side, so
|
If true, enables TCP keepalive messages to the other side, so
|
||||||
the daemon can terminate connections if the peer disappears.
|
the daemon can terminate connections if the peer disappears.
|
||||||
+
|
+
|
||||||
|
Only effective when `sshd.backend` is set to `MINA`.
|
||||||
|
+
|
||||||
By default, true.
|
By default, true.
|
||||||
|
|
||||||
[[sshd.threads]]sshd.threads::
|
[[sshd.threads]]sshd.threads::
|
||||||
|
|||||||
@@ -924,6 +924,84 @@ link:#diff-preferences-info[DiffPreferencesInfo] entity.
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Get Starred Changes
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
[verse]
|
||||||
|
'GET /accounts/link:#account-id[\{account-id\}]/starred.changes'
|
||||||
|
|
||||||
|
Gets the changes starred by the identified user account. This
|
||||||
|
URL endpoint is functionally identical to the changes query
|
||||||
|
`GET /changes/?q=is:starred`. The result is a list of
|
||||||
|
link:rest-api-changes.html#change-info[ChangeInfo] entities.
|
||||||
|
|
||||||
|
.Request
|
||||||
|
----
|
||||||
|
GET /a/accounts/self/starred.changes
|
||||||
|
----
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Disposition: attachment
|
||||||
|
Content-Type: application/json;charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"kind": "gerritcodereview#change",
|
||||||
|
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
|
||||||
|
"project": "myProject",
|
||||||
|
"branch": "master",
|
||||||
|
"change_id": "I8473b95934b5732ac55d26311a706c9c2bde9940",
|
||||||
|
"subject": "Implementing Feature X",
|
||||||
|
"status": "NEW",
|
||||||
|
"created": "2013-02-01 09:59:32.126000000",
|
||||||
|
"updated": "2013-02-21 11:16:36.775000000",
|
||||||
|
"mergeable": true,
|
||||||
|
"_sortkey": "0023412400000f7d",
|
||||||
|
"_number": 3965,
|
||||||
|
"owner": {
|
||||||
|
"name": "John Doe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
----
|
||||||
|
|
||||||
|
Star Change
|
||||||
|
~~~~~~~~~~~
|
||||||
|
[verse]
|
||||||
|
'PUT /accounts/link:#account-id[\{account-id\}]/starred.changes/link:rest-api-changes.html#change-id[\{change-id\}]'
|
||||||
|
|
||||||
|
Star a change. Starred changes are returned for the search query
|
||||||
|
`is:starred` or `starredby:USER` and automatically notify the user
|
||||||
|
whenever updates are made to the change.
|
||||||
|
|
||||||
|
.Request
|
||||||
|
----
|
||||||
|
PUT /a/accounts/self/starred.changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0
|
||||||
|
----
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 204 No Content
|
||||||
|
----
|
||||||
|
|
||||||
|
Unstar Change
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
[verse]
|
||||||
|
'DELETE /accounts/link:#account-id[\{account-id\}]/starred.changes/link:rest-api-changes#change-id[\{change-id\}]'
|
||||||
|
|
||||||
|
Unstar a change. Removes the starred flag, stopping notifications.
|
||||||
|
|
||||||
|
.Request
|
||||||
|
----
|
||||||
|
DELETE /a/accounts/self/starred.changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0
|
||||||
|
----
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 204 No Content
|
||||||
|
----
|
||||||
|
|
||||||
[[ids]]
|
[[ids]]
|
||||||
IDs
|
IDs
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ include_defs('//gerrit-acceptance-tests/tests.defs')
|
|||||||
|
|
||||||
acceptance_tests(
|
acceptance_tests(
|
||||||
srcs = glob(['*IT.java']),
|
srcs = glob(['*IT.java']),
|
||||||
deps = [':util'],
|
deps = [
|
||||||
|
':util',
|
||||||
|
'//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util',
|
||||||
|
'//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change:util',
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
java_library(
|
java_library(
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// Copyright (C) 2013 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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.google.gerrit.acceptance.rest.account;
|
||||||
|
|
||||||
|
import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
|
||||||
|
import static com.google.gerrit.acceptance.git.GitUtil.createProject;
|
||||||
|
import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.acceptance.AccountCreator;
|
||||||
|
import com.google.gerrit.acceptance.RestResponse;
|
||||||
|
import com.google.gerrit.acceptance.RestSession;
|
||||||
|
import com.google.gerrit.acceptance.SshSession;
|
||||||
|
import com.google.gerrit.acceptance.TestAccount;
|
||||||
|
import com.google.gerrit.acceptance.git.PushOneCommit;
|
||||||
|
import com.google.gerrit.acceptance.git.PushOneCommit.Result;
|
||||||
|
import com.google.gerrit.acceptance.rest.change.ChangeInfo;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.gwtorm.server.SchemaFactory;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StarredChangesIT extends AbstractDaemonTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private AccountCreator accounts;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SchemaFactory<ReviewDb> reviewDbProvider;
|
||||||
|
|
||||||
|
private TestAccount admin;
|
||||||
|
|
||||||
|
private RestSession session;
|
||||||
|
private Git git;
|
||||||
|
private ReviewDb db;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
admin = accounts.admin();
|
||||||
|
session = new RestSession(server, admin);
|
||||||
|
initSsh(admin);
|
||||||
|
Project.NameKey project = new Project.NameKey("p");
|
||||||
|
SshSession sshSession = new SshSession(server, admin);
|
||||||
|
createProject(sshSession, project.get());
|
||||||
|
git = cloneProject(sshSession.getUrl() + "/" + project.get());
|
||||||
|
sshSession.close();
|
||||||
|
db = reviewDbProvider.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void starredChangeState() throws GitAPIException, IOException,
|
||||||
|
OrmException {
|
||||||
|
Result c1 = createChange();
|
||||||
|
Result c2 = createChange();
|
||||||
|
assertNull(getChange(c1.getChangeId()).starred);
|
||||||
|
assertNull(getChange(c2.getChangeId()).starred);
|
||||||
|
starChange(true, c1.getPatchSetId().getParentKey());
|
||||||
|
starChange(true, c2.getPatchSetId().getParentKey());
|
||||||
|
assertTrue(getChange(c1.getChangeId()).starred);
|
||||||
|
assertTrue(getChange(c2.getChangeId()).starred);
|
||||||
|
starChange(false, c1.getPatchSetId().getParentKey());
|
||||||
|
starChange(false, c2.getPatchSetId().getParentKey());
|
||||||
|
assertNull(getChange(c1.getChangeId()).starred);
|
||||||
|
assertNull(getChange(c2.getChangeId()).starred);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChangeInfo getChange(String changeId) throws IOException {
|
||||||
|
RestResponse r = session.get("/changes/?q=" + changeId);
|
||||||
|
List<ChangeInfo> c = (new Gson()).fromJson(r.getReader(),
|
||||||
|
new TypeToken<List<ChangeInfo>>() {}.getType());
|
||||||
|
return c.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void starChange(boolean on, Change.Id id) throws IOException {
|
||||||
|
String url = "/accounts/self/starred.changes/" + id.get();
|
||||||
|
if (on) {
|
||||||
|
RestResponse r = session.put(url);
|
||||||
|
assertEquals(204, r.getStatusCode());
|
||||||
|
} else {
|
||||||
|
RestResponse r = session.delete(url);
|
||||||
|
assertEquals(204, r.getStatusCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result createChange() throws GitAPIException, IOException {
|
||||||
|
PushOneCommit push = new PushOneCommit(db, admin.getIdent());
|
||||||
|
return push.to(git, "refs/for/master");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,4 +38,5 @@ java_library(
|
|||||||
'//lib:guava',
|
'//lib:guava',
|
||||||
'//gerrit-reviewdb:server',
|
'//gerrit-reviewdb:server',
|
||||||
],
|
],
|
||||||
|
visibility = ['//gerrit-acceptance-tests/...'],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ public class ChangeInfo {
|
|||||||
String branch;
|
String branch;
|
||||||
List<ChangeMessageInfo> messages;
|
List<ChangeMessageInfo> messages;
|
||||||
Change.Status status;
|
Change.Status status;
|
||||||
|
public Boolean starred;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
// Copyright (C) 2008 The Android Open Source Project
|
|
||||||
//
|
|
||||||
// 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.google.gerrit.common.data;
|
|
||||||
|
|
||||||
import com.google.gerrit.common.audit.Audit;
|
|
||||||
import com.google.gerrit.common.auth.SignInRequired;
|
|
||||||
import com.google.gwtjsonrpc.common.AsyncCallback;
|
|
||||||
import com.google.gwtjsonrpc.common.RemoteJsonService;
|
|
||||||
import com.google.gwtjsonrpc.common.RpcImpl;
|
|
||||||
import com.google.gwtjsonrpc.common.VoidResult;
|
|
||||||
import com.google.gwtjsonrpc.common.RpcImpl.Version;
|
|
||||||
|
|
||||||
@RpcImpl(version = Version.V2_0)
|
|
||||||
public interface ChangeListService extends RemoteJsonService {
|
|
||||||
/**
|
|
||||||
* Add and/or remove changes from the set of starred changes of the caller.
|
|
||||||
*
|
|
||||||
* @param req the add and remove cluster.
|
|
||||||
*/
|
|
||||||
@Audit
|
|
||||||
@SignInRequired
|
|
||||||
void toggleStars(ToggleStarRequest req, AsyncCallback<VoidResult> callback);
|
|
||||||
}
|
|
||||||
@@ -15,19 +15,23 @@
|
|||||||
package com.google.gerrit.client.changes;
|
package com.google.gerrit.client.changes;
|
||||||
|
|
||||||
import com.google.gerrit.client.Gerrit;
|
import com.google.gerrit.client.Gerrit;
|
||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
import com.google.gerrit.client.account.AccountApi;
|
||||||
import com.google.gerrit.common.data.ToggleStarRequest;
|
import com.google.gerrit.client.rpc.RestApi;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
import com.google.gwt.event.dom.client.ClickHandler;
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
import com.google.gwt.event.dom.client.KeyPressEvent;
|
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||||
import com.google.gwt.resources.client.ImageResource;
|
import com.google.gwt.resources.client.ImageResource;
|
||||||
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.google.gwt.user.client.ui.Image;
|
import com.google.gwt.user.client.ui.Image;
|
||||||
import com.google.gwtexpui.globalkey.client.KeyCommand;
|
import com.google.gwtexpui.globalkey.client.KeyCommand;
|
||||||
import com.google.gwtjsonrpc.common.VoidResult;
|
|
||||||
import com.google.web.bindery.event.shared.Event;
|
import com.google.web.bindery.event.shared.Event;
|
||||||
import com.google.web.bindery.event.shared.HandlerRegistration;
|
import com.google.web.bindery.event.shared.HandlerRegistration;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/** Supports the star icon displayed on changes and tracking the status. */
|
/** Supports the star icon displayed on changes and tracking the status. */
|
||||||
public class StarredChanges {
|
public class StarredChanges {
|
||||||
private static final Event.Type<ChangeStarHandler> TYPE =
|
private static final Event.Type<ChangeStarHandler> TYPE =
|
||||||
@@ -105,57 +109,52 @@ public class StarredChanges {
|
|||||||
public static void toggleStar(
|
public static void toggleStar(
|
||||||
final Change.Id changeId,
|
final Change.Id changeId,
|
||||||
final boolean newValue) {
|
final boolean newValue) {
|
||||||
if (next == null) {
|
pending.put(changeId, newValue);
|
||||||
next = new ToggleStarRequest();
|
|
||||||
}
|
|
||||||
next.toggle(changeId, newValue);
|
|
||||||
fireChangeStarEvent(changeId, newValue);
|
fireChangeStarEvent(changeId, newValue);
|
||||||
if (!busy) {
|
if (!busy) {
|
||||||
start();
|
startRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ToggleStarRequest next;
|
|
||||||
private static boolean busy;
|
private static boolean busy;
|
||||||
|
private static final Map<Change.Id, Boolean> pending =
|
||||||
|
new LinkedHashMap<Change.Id, Boolean>(4);
|
||||||
|
|
||||||
private static void start() {
|
private static void startRequest() {
|
||||||
final ToggleStarRequest req = next;
|
|
||||||
next = null;
|
|
||||||
busy = true;
|
busy = true;
|
||||||
|
|
||||||
Util.LIST_SVC.toggleStars(req, new GerritCallback<VoidResult>() {
|
final Change.Id id = pending.keySet().iterator().next();
|
||||||
|
final boolean starred = pending.remove(id);
|
||||||
|
RestApi call = AccountApi.self().view("starred.changes").id(id.get());
|
||||||
|
AsyncCallback<JavaScriptObject> cb = new AsyncCallback<JavaScriptObject>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(VoidResult result) {
|
public void onSuccess(JavaScriptObject none) {
|
||||||
if (next != null) {
|
if (pending.isEmpty()) {
|
||||||
start();
|
|
||||||
} else {
|
|
||||||
busy = false;
|
busy = false;
|
||||||
|
} else {
|
||||||
|
startRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Throwable caught) {
|
public void onFailure(Throwable caught) {
|
||||||
rollback(req);
|
if (!starred && RestApi.isStatus(caught, 404)) {
|
||||||
if (next != null) {
|
onSuccess(null);
|
||||||
rollback(next);
|
return;
|
||||||
next = null;
|
|
||||||
}
|
|
||||||
busy = false;
|
|
||||||
super.onFailure(caught);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void rollback(ToggleStarRequest req) {
|
fireChangeStarEvent(id, !starred);
|
||||||
if (req.getAddSet() != null) {
|
for (Map.Entry<Change.Id, Boolean> e : pending.entrySet()) {
|
||||||
for (Change.Id id : req.getAddSet()) {
|
fireChangeStarEvent(e.getKey(), !e.getValue());
|
||||||
fireChangeStarEvent(id, false);
|
|
||||||
}
|
}
|
||||||
|
pending.clear();
|
||||||
|
busy = false;
|
||||||
}
|
}
|
||||||
if (req.getRemoveSet() != null) {
|
};
|
||||||
for (Change.Id id : req.getRemoveSet()) {
|
if (starred) {
|
||||||
fireChangeStarEvent(id, true);
|
call.put(cb);
|
||||||
}
|
} else {
|
||||||
|
call.delete(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
package com.google.gerrit.client.changes;
|
package com.google.gerrit.client.changes;
|
||||||
|
|
||||||
import com.google.gerrit.common.data.ChangeDetailService;
|
import com.google.gerrit.common.data.ChangeDetailService;
|
||||||
import com.google.gerrit.common.data.ChangeListService;
|
|
||||||
import com.google.gerrit.common.data.ChangeManageService;
|
import com.google.gerrit.common.data.ChangeManageService;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
@@ -27,7 +26,6 @@ public class Util {
|
|||||||
public static final ChangeResources R = GWT.create(ChangeResources.class);
|
public static final ChangeResources R = GWT.create(ChangeResources.class);
|
||||||
|
|
||||||
public static final ChangeDetailService DETAIL_SVC;
|
public static final ChangeDetailService DETAIL_SVC;
|
||||||
public static final ChangeListService LIST_SVC;
|
|
||||||
public static final ChangeManageService MANAGE_SVC;
|
public static final ChangeManageService MANAGE_SVC;
|
||||||
|
|
||||||
private static final int SUBJECT_MAX_LENGTH = 80;
|
private static final int SUBJECT_MAX_LENGTH = 80;
|
||||||
@@ -38,9 +36,6 @@ public class Util {
|
|||||||
DETAIL_SVC = GWT.create(ChangeDetailService.class);
|
DETAIL_SVC = GWT.create(ChangeDetailService.class);
|
||||||
JsonUtil.bind(DETAIL_SVC, "rpc/ChangeDetailService");
|
JsonUtil.bind(DETAIL_SVC, "rpc/ChangeDetailService");
|
||||||
|
|
||||||
LIST_SVC = GWT.create(ChangeListService.class);
|
|
||||||
JsonUtil.bind(LIST_SVC, "rpc/ChangeListService");
|
|
||||||
|
|
||||||
MANAGE_SVC = GWT.create(ChangeManageService.class);
|
MANAGE_SVC = GWT.create(ChangeManageService.class);
|
||||||
JsonUtil.bind(MANAGE_SVC, "rpc/ChangeManageService");
|
JsonUtil.bind(MANAGE_SVC, "rpc/ChangeManageService");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
// Copyright (C) 2008 The Android Open Source Project
|
|
||||||
//
|
|
||||||
// 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.google.gerrit.httpd.rpc;
|
|
||||||
|
|
||||||
import com.google.gerrit.common.data.ChangeListService;
|
|
||||||
import com.google.gerrit.common.data.ToggleStarRequest;
|
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
|
||||||
import com.google.gerrit.reviewdb.client.StarredChange;
|
|
||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
|
||||||
import com.google.gerrit.server.CurrentUser;
|
|
||||||
import com.google.gwtjsonrpc.common.AsyncCallback;
|
|
||||||
import com.google.gwtjsonrpc.common.VoidResult;
|
|
||||||
import com.google.gwtorm.server.OrmException;
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import com.google.inject.Provider;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class ChangeListServiceImpl extends BaseServiceImplementation implements
|
|
||||||
ChangeListService {
|
|
||||||
private final Provider<CurrentUser> currentUser;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
ChangeListServiceImpl(final Provider<ReviewDb> schema,
|
|
||||||
final Provider<CurrentUser> currentUser) {
|
|
||||||
super(schema, currentUser);
|
|
||||||
this.currentUser = currentUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleStars(final ToggleStarRequest req,
|
|
||||||
final AsyncCallback<VoidResult> callback) {
|
|
||||||
run(callback, new Action<VoidResult>() {
|
|
||||||
public VoidResult run(final ReviewDb db) throws OrmException {
|
|
||||||
final Account.Id me = getAccountId();
|
|
||||||
final Set<Change.Id> existing = currentUser.get().getStarredChanges();
|
|
||||||
List<StarredChange> add = new ArrayList<StarredChange>();
|
|
||||||
List<StarredChange.Key> remove = new ArrayList<StarredChange.Key>();
|
|
||||||
|
|
||||||
if (req.getAddSet() != null) {
|
|
||||||
for (final Change.Id id : req.getAddSet()) {
|
|
||||||
if (!existing.contains(id)) {
|
|
||||||
add.add(new StarredChange(new StarredChange.Key(me, id)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.getRemoveSet() != null) {
|
|
||||||
for (final Change.Id id : req.getRemoveSet()) {
|
|
||||||
remove.add(new StarredChange.Key(me, id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db.starredChanges().insert(add);
|
|
||||||
db.starredChanges().deleteKeys(remove);
|
|
||||||
return VoidResult.INSTANCE;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,6 @@ public class UiRpcModule extends RpcServletModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configureServlets() {
|
protected void configureServlets() {
|
||||||
rpc(ChangeListServiceImpl.class);
|
|
||||||
rpc(SuggestServiceImpl.class);
|
rpc(SuggestServiceImpl.class);
|
||||||
rpc(SystemInfoServiceImpl.class);
|
rpc(SystemInfoServiceImpl.class);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ package com.google.gerrit.server.account;
|
|||||||
import com.google.gerrit.extensions.restapi.RestResource;
|
import com.google.gerrit.extensions.restapi.RestResource;
|
||||||
import com.google.gerrit.extensions.restapi.RestView;
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
import com.google.gerrit.reviewdb.client.AccountSshKey;
|
import com.google.gerrit.reviewdb.client.AccountSshKey;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.change.ChangeResource;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
public class AccountResource implements RestResource {
|
public class AccountResource implements RestResource {
|
||||||
@@ -33,6 +35,9 @@ public class AccountResource implements RestResource {
|
|||||||
public static final TypeLiteral<RestView<SshKey>> SSH_KEY_KIND =
|
public static final TypeLiteral<RestView<SshKey>> SSH_KEY_KIND =
|
||||||
new TypeLiteral<RestView<SshKey>>() {};
|
new TypeLiteral<RestView<SshKey>>() {};
|
||||||
|
|
||||||
|
public static final TypeLiteral<RestView<StarredChange>> STARRED_CHANGE_KIND =
|
||||||
|
new TypeLiteral<RestView<StarredChange>>() {};
|
||||||
|
|
||||||
private final IdentifiedUser user;
|
private final IdentifiedUser user;
|
||||||
|
|
||||||
public AccountResource(IdentifiedUser user) {
|
public AccountResource(IdentifiedUser user) {
|
||||||
@@ -90,4 +95,17 @@ public class AccountResource implements RestResource {
|
|||||||
return sshKey;
|
return sshKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class StarredChange extends AccountResource {
|
||||||
|
private final ChangeResource change;
|
||||||
|
|
||||||
|
public StarredChange(IdentifiedUser user, ChangeResource change) {
|
||||||
|
super(user);
|
||||||
|
this.change = change;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Change getChange() {
|
||||||
|
return change.getChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import static com.google.gerrit.server.account.AccountResource.ACCOUNT_KIND;
|
|||||||
import static com.google.gerrit.server.account.AccountResource.CAPABILITY_KIND;
|
import static com.google.gerrit.server.account.AccountResource.CAPABILITY_KIND;
|
||||||
import static com.google.gerrit.server.account.AccountResource.EMAIL_KIND;
|
import static com.google.gerrit.server.account.AccountResource.EMAIL_KIND;
|
||||||
import static com.google.gerrit.server.account.AccountResource.SSH_KEY_KIND;
|
import static com.google.gerrit.server.account.AccountResource.SSH_KEY_KIND;
|
||||||
|
import static com.google.gerrit.server.account.AccountResource.STARRED_CHANGE_KIND;
|
||||||
|
|
||||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||||
@@ -30,9 +31,10 @@ public class Module extends RestApiModule {
|
|||||||
bind(Capabilities.class);
|
bind(Capabilities.class);
|
||||||
|
|
||||||
DynamicMap.mapOf(binder(), ACCOUNT_KIND);
|
DynamicMap.mapOf(binder(), ACCOUNT_KIND);
|
||||||
|
DynamicMap.mapOf(binder(), CAPABILITY_KIND);
|
||||||
DynamicMap.mapOf(binder(), EMAIL_KIND);
|
DynamicMap.mapOf(binder(), EMAIL_KIND);
|
||||||
DynamicMap.mapOf(binder(), SSH_KEY_KIND);
|
DynamicMap.mapOf(binder(), SSH_KEY_KIND);
|
||||||
DynamicMap.mapOf(binder(), CAPABILITY_KIND);
|
DynamicMap.mapOf(binder(), STARRED_CHANGE_KIND);
|
||||||
|
|
||||||
put(ACCOUNT_KIND).to(PutAccount.class);
|
put(ACCOUNT_KIND).to(PutAccount.class);
|
||||||
get(ACCOUNT_KIND).to(GetAccount.class);
|
get(ACCOUNT_KIND).to(GetAccount.class);
|
||||||
@@ -65,6 +67,11 @@ public class Module extends RestApiModule {
|
|||||||
put(ACCOUNT_KIND, "preferences.diff").to(SetDiffPreferences.class);
|
put(ACCOUNT_KIND, "preferences.diff").to(SetDiffPreferences.class);
|
||||||
get(CAPABILITY_KIND).to(GetCapabilities.CheckOne.class);
|
get(CAPABILITY_KIND).to(GetCapabilities.CheckOne.class);
|
||||||
|
|
||||||
|
child(ACCOUNT_KIND, "starred.changes").to(StarredChanges.class);
|
||||||
|
put(STARRED_CHANGE_KIND).to(StarredChanges.Put.class);
|
||||||
|
delete(STARRED_CHANGE_KIND).to(StarredChanges.Delete.class);
|
||||||
|
bind(StarredChanges.Create.class);
|
||||||
|
|
||||||
install(new FactoryModuleBuilder().build(CreateAccount.Factory.class));
|
install(new FactoryModuleBuilder().build(CreateAccount.Factory.class));
|
||||||
install(new FactoryModuleBuilder().build(CreateEmail.Factory.class));
|
install(new FactoryModuleBuilder().build(CreateEmail.Factory.class));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
// Copyright (C) 2013 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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.google.gerrit.server.account;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||||
|
import com.google.gerrit.extensions.restapi.AcceptsCreate;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.extensions.restapi.ChildCollection;
|
||||||
|
import com.google.gerrit.extensions.restapi.IdString;
|
||||||
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
|
import com.google.gerrit.extensions.restapi.Response;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
|
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||||
|
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||||
|
import com.google.gerrit.reviewdb.client.StarredChange;
|
||||||
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gerrit.server.CurrentUser;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.change.ChangeResource;
|
||||||
|
import com.google.gerrit.server.change.ChangesCollection;
|
||||||
|
import com.google.gerrit.server.query.change.QueryChanges;
|
||||||
|
import com.google.gwtorm.server.OrmDuplicateKeyException;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
class StarredChanges implements
|
||||||
|
ChildCollection<AccountResource, AccountResource.StarredChange>,
|
||||||
|
AcceptsCreate<AccountResource> {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(StarredChanges.class);
|
||||||
|
|
||||||
|
private final ChangesCollection changes;
|
||||||
|
private final DynamicMap<RestView<AccountResource.StarredChange>> views;
|
||||||
|
private final Provider<Create> createProvider;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
StarredChanges(ChangesCollection changes,
|
||||||
|
DynamicMap<RestView<AccountResource.StarredChange>> views,
|
||||||
|
Provider<Create> createProvider) {
|
||||||
|
this.changes = changes;
|
||||||
|
this.views = views;
|
||||||
|
this.createProvider = createProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccountResource.StarredChange parse(AccountResource parent, IdString id)
|
||||||
|
throws ResourceNotFoundException, OrmException {
|
||||||
|
IdentifiedUser user = parent.getUser();
|
||||||
|
try {
|
||||||
|
user.asyncStarredChanges();
|
||||||
|
|
||||||
|
ChangeResource change = changes.parse(TopLevelResource.INSTANCE, id);
|
||||||
|
if (user.getStarredChanges().contains(change.getChange().getId())) {
|
||||||
|
return new AccountResource.StarredChange(user, change);
|
||||||
|
}
|
||||||
|
throw new ResourceNotFoundException(id);
|
||||||
|
} finally {
|
||||||
|
user.abortStarredChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DynamicMap<RestView<AccountResource.StarredChange>> views() {
|
||||||
|
return views;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RestView<AccountResource> list() throws ResourceNotFoundException {
|
||||||
|
return new RestReadView<AccountResource>() {
|
||||||
|
@Override
|
||||||
|
public Object apply(AccountResource self) throws BadRequestException,
|
||||||
|
AuthException, OrmException {
|
||||||
|
QueryChanges query = changes.list();
|
||||||
|
query.addQuery("starredby:" + self.getUser().getAccountId().get());
|
||||||
|
return query.apply(TopLevelResource.INSTANCE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public RestModifyView<AccountResource, EmptyInput> create(
|
||||||
|
AccountResource parent, IdString id) throws UnprocessableEntityException{
|
||||||
|
try {
|
||||||
|
return createProvider.get()
|
||||||
|
.setChange(changes.parse(TopLevelResource.INSTANCE, id));
|
||||||
|
} catch (ResourceNotFoundException e) {
|
||||||
|
throw new UnprocessableEntityException(String.format("change %s not found", id.get()));
|
||||||
|
} catch (OrmException e) {
|
||||||
|
log.error("cannot resolve change", e);
|
||||||
|
throw new UnprocessableEntityException("internal server error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Create implements RestModifyView<AccountResource, EmptyInput> {
|
||||||
|
private final Provider<CurrentUser> self;
|
||||||
|
private final Provider<ReviewDb> dbProvider;
|
||||||
|
private ChangeResource change;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Create(Provider<CurrentUser> self, Provider<ReviewDb> dbProvider) {
|
||||||
|
this.self = self;
|
||||||
|
this.dbProvider = dbProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
Create setChange(ChangeResource change) {
|
||||||
|
this.change = change;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<?> apply(AccountResource rsrc, EmptyInput in)
|
||||||
|
throws AuthException, OrmException {
|
||||||
|
if (self.get() != rsrc.getUser()) {
|
||||||
|
throw new AuthException("not allowed to add starred change");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dbProvider.get().starredChanges().insert(Collections.singleton(
|
||||||
|
new StarredChange(new StarredChange.Key(
|
||||||
|
rsrc.getUser().getAccountId(),
|
||||||
|
change.getChange().getId()))));
|
||||||
|
} catch (OrmDuplicateKeyException e) {
|
||||||
|
return Response.none();
|
||||||
|
}
|
||||||
|
return Response.none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Put implements
|
||||||
|
RestModifyView<AccountResource.StarredChange, EmptyInput> {
|
||||||
|
private final Provider<CurrentUser> self;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Put(Provider<CurrentUser> self) {
|
||||||
|
this.self = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<?> apply(AccountResource.StarredChange rsrc, EmptyInput in)
|
||||||
|
throws AuthException, OrmException {
|
||||||
|
if (self.get() != rsrc.getUser()) {
|
||||||
|
throw new AuthException("not allowed update starred changes");
|
||||||
|
}
|
||||||
|
return Response.none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Delete implements
|
||||||
|
RestModifyView<AccountResource.StarredChange, EmptyInput> {
|
||||||
|
private final Provider<CurrentUser> self;
|
||||||
|
private final Provider<ReviewDb> dbProvider;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Delete(Provider<CurrentUser> self, Provider<ReviewDb> dbProvider) {
|
||||||
|
this.self = self;
|
||||||
|
this.dbProvider = dbProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<?> apply(AccountResource.StarredChange rsrc,
|
||||||
|
EmptyInput in) throws AuthException, OrmException {
|
||||||
|
if (self.get() != rsrc.getUser()) {
|
||||||
|
throw new AuthException("not allowed remove starred change");
|
||||||
|
}
|
||||||
|
dbProvider.get().starredChanges().delete(Collections.singleton(
|
||||||
|
new StarredChange(new StarredChange.Key(
|
||||||
|
rsrc.getUser().getAccountId(),
|
||||||
|
rsrc.getChange().getId()))));
|
||||||
|
return Response.none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class EmptyInput {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ public class ChangesCollection implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestView<TopLevelResource> list() {
|
public QueryChanges list() {
|
||||||
return queryFactory.get();
|
return queryFactory.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (C) 2013 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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.google.gerrit.sshd;
|
||||||
|
|
||||||
|
import org.apache.sshd.common.future.CloseFuture;
|
||||||
|
import org.apache.sshd.common.future.SshFutureListener;
|
||||||
|
import org.apache.sshd.common.io.IoSession;
|
||||||
|
import org.apache.sshd.server.ServerFactoryManager;
|
||||||
|
import org.apache.sshd.server.session.ServerSession;
|
||||||
|
|
||||||
|
/* Expose addition of close session listeners */
|
||||||
|
class GerritServerSession extends ServerSession {
|
||||||
|
|
||||||
|
GerritServerSession(ServerFactoryManager server,
|
||||||
|
IoSession ioSession) throws Exception {
|
||||||
|
super(server, ioSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCloseSessionListener(SshFutureListener<CloseFuture> l) {
|
||||||
|
closeFuture.addListener(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
package com.google.gerrit.sshd;
|
package com.google.gerrit.sshd;
|
||||||
|
|
||||||
import static com.google.gerrit.server.ssh.SshAddressesModule.IANA_SSH_PORT;
|
import static com.google.gerrit.server.ssh.SshAddressesModule.IANA_SSH_PORT;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
@@ -35,20 +34,18 @@ import com.google.inject.Singleton;
|
|||||||
import com.jcraft.jsch.HostKey;
|
import com.jcraft.jsch.HostKey;
|
||||||
import com.jcraft.jsch.JSchException;
|
import com.jcraft.jsch.JSchException;
|
||||||
|
|
||||||
import org.apache.mina.core.future.IoFuture;
|
|
||||||
import org.apache.mina.core.future.IoFutureListener;
|
|
||||||
import org.apache.mina.core.service.IoAcceptor;
|
|
||||||
import org.apache.mina.core.session.IoSession;
|
|
||||||
import org.apache.mina.transport.socket.SocketSessionConfig;
|
import org.apache.mina.transport.socket.SocketSessionConfig;
|
||||||
import org.apache.sshd.SshServer;
|
import org.apache.sshd.SshServer;
|
||||||
import org.apache.sshd.common.Channel;
|
import org.apache.sshd.common.Channel;
|
||||||
import org.apache.sshd.common.Cipher;
|
import org.apache.sshd.common.Cipher;
|
||||||
import org.apache.sshd.common.Compression;
|
import org.apache.sshd.common.Compression;
|
||||||
|
import org.apache.sshd.common.ForwardingFilter;
|
||||||
import org.apache.sshd.common.KeyExchange;
|
import org.apache.sshd.common.KeyExchange;
|
||||||
import org.apache.sshd.common.KeyPairProvider;
|
import org.apache.sshd.common.KeyPairProvider;
|
||||||
import org.apache.sshd.common.NamedFactory;
|
import org.apache.sshd.common.NamedFactory;
|
||||||
import org.apache.sshd.common.Session;
|
import org.apache.sshd.common.Session;
|
||||||
import org.apache.sshd.common.Signature;
|
import org.apache.sshd.common.Signature;
|
||||||
|
import org.apache.sshd.common.SshdSocketAddress;
|
||||||
import org.apache.sshd.common.cipher.AES128CBC;
|
import org.apache.sshd.common.cipher.AES128CBC;
|
||||||
import org.apache.sshd.common.cipher.AES192CBC;
|
import org.apache.sshd.common.cipher.AES192CBC;
|
||||||
import org.apache.sshd.common.cipher.AES256CBC;
|
import org.apache.sshd.common.cipher.AES256CBC;
|
||||||
@@ -56,6 +53,19 @@ import org.apache.sshd.common.cipher.BlowfishCBC;
|
|||||||
import org.apache.sshd.common.cipher.CipherNone;
|
import org.apache.sshd.common.cipher.CipherNone;
|
||||||
import org.apache.sshd.common.cipher.TripleDESCBC;
|
import org.apache.sshd.common.cipher.TripleDESCBC;
|
||||||
import org.apache.sshd.common.compression.CompressionNone;
|
import org.apache.sshd.common.compression.CompressionNone;
|
||||||
|
import org.apache.sshd.common.file.FileSystemFactory;
|
||||||
|
import org.apache.sshd.common.file.FileSystemView;
|
||||||
|
import org.apache.sshd.common.file.SshFile;
|
||||||
|
import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
|
||||||
|
import org.apache.sshd.common.forward.TcpipServerChannel;
|
||||||
|
import org.apache.sshd.common.future.CloseFuture;
|
||||||
|
import org.apache.sshd.common.future.SshFutureListener;
|
||||||
|
import org.apache.sshd.common.io.IoAcceptor;
|
||||||
|
import org.apache.sshd.common.io.IoServiceFactory;
|
||||||
|
import org.apache.sshd.common.io.IoSession;
|
||||||
|
import org.apache.sshd.common.io.mina.MinaServiceFactory;
|
||||||
|
import org.apache.sshd.common.io.mina.MinaSession;
|
||||||
|
import org.apache.sshd.common.io.nio2.Nio2ServiceFactory;
|
||||||
import org.apache.sshd.common.mac.HMACMD5;
|
import org.apache.sshd.common.mac.HMACMD5;
|
||||||
import org.apache.sshd.common.mac.HMACMD596;
|
import org.apache.sshd.common.mac.HMACMD596;
|
||||||
import org.apache.sshd.common.mac.HMACSHA1;
|
import org.apache.sshd.common.mac.HMACSHA1;
|
||||||
@@ -63,26 +73,21 @@ import org.apache.sshd.common.mac.HMACSHA196;
|
|||||||
import org.apache.sshd.common.random.BouncyCastleRandom;
|
import org.apache.sshd.common.random.BouncyCastleRandom;
|
||||||
import org.apache.sshd.common.random.JceRandom;
|
import org.apache.sshd.common.random.JceRandom;
|
||||||
import org.apache.sshd.common.random.SingletonRandomFactory;
|
import org.apache.sshd.common.random.SingletonRandomFactory;
|
||||||
|
import org.apache.sshd.common.session.AbstractSession;
|
||||||
import org.apache.sshd.common.signature.SignatureDSA;
|
import org.apache.sshd.common.signature.SignatureDSA;
|
||||||
import org.apache.sshd.common.signature.SignatureRSA;
|
import org.apache.sshd.common.signature.SignatureRSA;
|
||||||
import org.apache.sshd.common.util.Buffer;
|
import org.apache.sshd.common.util.Buffer;
|
||||||
import org.apache.sshd.common.util.SecurityUtils;
|
import org.apache.sshd.common.util.SecurityUtils;
|
||||||
import org.apache.sshd.server.Command;
|
import org.apache.sshd.server.Command;
|
||||||
import org.apache.sshd.server.CommandFactory;
|
import org.apache.sshd.server.CommandFactory;
|
||||||
import org.apache.sshd.server.FileSystemFactory;
|
|
||||||
import org.apache.sshd.server.FileSystemView;
|
|
||||||
import org.apache.sshd.server.ForwardingFilter;
|
|
||||||
import org.apache.sshd.server.PublickeyAuthenticator;
|
import org.apache.sshd.server.PublickeyAuthenticator;
|
||||||
import org.apache.sshd.server.SshFile;
|
|
||||||
import org.apache.sshd.server.UserAuth;
|
import org.apache.sshd.server.UserAuth;
|
||||||
import org.apache.sshd.server.auth.UserAuthPublicKey;
|
import org.apache.sshd.server.auth.UserAuthPublicKey;
|
||||||
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
|
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
|
||||||
import org.apache.sshd.server.auth.gss.UserAuthGSS;
|
import org.apache.sshd.server.auth.gss.UserAuthGSS;
|
||||||
import org.apache.sshd.server.channel.ChannelDirectTcpip;
|
|
||||||
import org.apache.sshd.server.channel.ChannelSession;
|
import org.apache.sshd.server.channel.ChannelSession;
|
||||||
import org.apache.sshd.server.kex.DHG1;
|
import org.apache.sshd.server.kex.DHG1;
|
||||||
import org.apache.sshd.server.kex.DHG14;
|
import org.apache.sshd.server.kex.DHG14;
|
||||||
import org.apache.sshd.server.session.ServerSession;
|
|
||||||
import org.apache.sshd.server.session.SessionFactory;
|
import org.apache.sshd.server.session.SessionFactory;
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -91,7 +96,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
@@ -126,6 +130,11 @@ import java.util.List;
|
|||||||
public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SshDaemon.class);
|
private static final Logger log = LoggerFactory.getLogger(SshDaemon.class);
|
||||||
|
|
||||||
|
public static enum SshSessionBackend {
|
||||||
|
MINA,
|
||||||
|
NIO2
|
||||||
|
}
|
||||||
|
|
||||||
private final List<SocketAddress> listen;
|
private final List<SocketAddress> listen;
|
||||||
private final List<String> advertised;
|
private final List<String> advertised;
|
||||||
private final boolean keepAlive;
|
private final boolean keepAlive;
|
||||||
@@ -144,7 +153,6 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
|
|
||||||
this.listen = listen;
|
this.listen = listen;
|
||||||
this.advertised = advertised;
|
this.advertised = advertised;
|
||||||
reuseAddress = cfg.getBoolean("sshd", "reuseaddress", true);
|
|
||||||
keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true);
|
keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true);
|
||||||
|
|
||||||
getProperties().put(SERVER_IDENTIFICATION,
|
getProperties().put(SERVER_IDENTIFICATION,
|
||||||
@@ -161,12 +169,6 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
|
|
||||||
long idleTimeoutSeconds = ConfigUtil.getTimeUnit(cfg, "sshd", null,
|
long idleTimeoutSeconds = ConfigUtil.getTimeUnit(cfg, "sshd", null,
|
||||||
"idleTimeout", 0, SECONDS);
|
"idleTimeout", 0, SECONDS);
|
||||||
if (idleTimeoutSeconds == 0) {
|
|
||||||
// Since Apache SSHD does not allow to turn off closing idle connections,
|
|
||||||
// we fake it by using the highest timeout allowed by Apache SSHD, which
|
|
||||||
// amounts to ~24 days.
|
|
||||||
idleTimeoutSeconds = MILLISECONDS.toSeconds(Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
getProperties().put(
|
getProperties().put(
|
||||||
IDLE_TIMEOUT,
|
IDLE_TIMEOUT,
|
||||||
String.valueOf(SECONDS.toMillis(idleTimeoutSeconds)));
|
String.valueOf(SECONDS.toMillis(idleTimeoutSeconds)));
|
||||||
@@ -183,6 +185,14 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
final String kerberosPrincipal = cfg.getString(
|
final String kerberosPrincipal = cfg.getString(
|
||||||
"sshd", null, "kerberosPrincipal");
|
"sshd", null, "kerberosPrincipal");
|
||||||
|
|
||||||
|
SshSessionBackend backend = cfg.getEnum(
|
||||||
|
"sshd", null, "backend", SshSessionBackend.MINA);
|
||||||
|
|
||||||
|
System.setProperty(IoServiceFactory.class.getName(),
|
||||||
|
backend == SshSessionBackend.MINA
|
||||||
|
? MinaServiceFactory.class.getName()
|
||||||
|
: Nio2ServiceFactory.class.getName());
|
||||||
|
|
||||||
if (SecurityUtils.isBouncyCastleRegistered()) {
|
if (SecurityUtils.isBouncyCastleRegistered()) {
|
||||||
initProviderBouncyCastle();
|
initProviderBouncyCastle();
|
||||||
} else {
|
} else {
|
||||||
@@ -192,7 +202,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
initMacs(cfg);
|
initMacs(cfg);
|
||||||
initSignatures();
|
initSignatures();
|
||||||
initChannels();
|
initChannels();
|
||||||
initForwardingFilter();
|
initForwarding();
|
||||||
initFileSystemFactory();
|
initFileSystemFactory();
|
||||||
initSubsystems();
|
initSubsystems();
|
||||||
initCompression();
|
initCompression();
|
||||||
@@ -202,24 +212,28 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
setShellFactory(noShell);
|
setShellFactory(noShell);
|
||||||
setSessionFactory(new SessionFactory() {
|
setSessionFactory(new SessionFactory() {
|
||||||
@Override
|
@Override
|
||||||
protected ServerSession createSession(final IoSession io)
|
protected AbstractSession createSession(final IoSession io)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
if (io.getConfig() instanceof SocketSessionConfig) {
|
if (io instanceof MinaSession) {
|
||||||
final SocketSessionConfig c = (SocketSessionConfig) io.getConfig();
|
if (((MinaSession) io).getSession()
|
||||||
c.setKeepAlive(keepAlive);
|
.getConfig() instanceof SocketSessionConfig) {
|
||||||
|
((SocketSessionConfig) ((MinaSession) io).getSession()
|
||||||
|
.getConfig())
|
||||||
|
.setKeepAlive(keepAlive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServerSession s = (ServerSession) super.createSession(io);
|
GerritServerSession s = (GerritServerSession)super.createSession(io);
|
||||||
final int id = idGenerator.next();
|
int id = idGenerator.next();
|
||||||
final SocketAddress peer = io.getRemoteAddress();
|
SocketAddress peer = io.getRemoteAddress();
|
||||||
final SshSession sd = new SshSession(id, peer);
|
final SshSession sd = new SshSession(id, peer);
|
||||||
s.setAttribute(SshSession.KEY, sd);
|
s.setAttribute(SshSession.KEY, sd);
|
||||||
|
|
||||||
// Log a session close without authentication as a failure.
|
// Log a session close without authentication as a failure.
|
||||||
//
|
//
|
||||||
io.getCloseFuture().addListener(new IoFutureListener<IoFuture>() {
|
s.addCloseSessionListener(new SshFutureListener<CloseFuture>() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(IoFuture future) {
|
public void operationComplete(CloseFuture future) {
|
||||||
if (sd.isAuthenticationError()) {
|
if (sd.isAuthenticationError()) {
|
||||||
sshLog.onAuthFail(sd);
|
sshLog.onAuthFail(sd);
|
||||||
}
|
}
|
||||||
@@ -227,6 +241,12 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
});
|
});
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractSession doCreateSession(IoSession ioSession)
|
||||||
|
throws Exception {
|
||||||
|
return new GerritServerSession(server, ioSession);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
hostKeys = computeHostKeys();
|
hostKeys = computeHostKeys();
|
||||||
@@ -245,13 +265,11 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
public synchronized void start() {
|
public synchronized void start() {
|
||||||
if (acceptor == null && !listen.isEmpty()) {
|
if (acceptor == null && !listen.isEmpty()) {
|
||||||
checkConfig();
|
checkConfig();
|
||||||
|
if (sessionFactory == null) {
|
||||||
|
sessionFactory = createSessionFactory();
|
||||||
|
}
|
||||||
|
sessionFactory.setServer(this);
|
||||||
acceptor = createAcceptor();
|
acceptor = createAcceptor();
|
||||||
configure(acceptor);
|
|
||||||
|
|
||||||
final SessionFactory handler = getSessionFactory();
|
|
||||||
handler.setServer(this);
|
|
||||||
acceptor.setHandler(handler);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
acceptor.bind(listen);
|
acceptor.bind(listen);
|
||||||
@@ -259,7 +277,8 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
throw new IllegalStateException("Cannot bind to " + addressList(), e);
|
throw new IllegalStateException("Cannot bind to " + addressList(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Started Gerrit SSHD on " + addressList());
|
log.info(String.format("Started Gerrit %s on %s",
|
||||||
|
version, addressList()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +492,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
private void initChannels() {
|
private void initChannels() {
|
||||||
setChannelFactories(Arrays.<NamedFactory<Channel>> asList(
|
setChannelFactories(Arrays.<NamedFactory<Channel>> asList(
|
||||||
new ChannelSession.Factory(), //
|
new ChannelSession.Factory(), //
|
||||||
new ChannelDirectTcpip.Factory() //
|
new TcpipServerChannel.DirectTcpipFactory() //
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,28 +533,29 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
|||||||
setPublickeyAuthenticator(pubkey);
|
setPublickeyAuthenticator(pubkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initForwardingFilter() {
|
private void initForwarding() {
|
||||||
setForwardingFilter(new ForwardingFilter() {
|
setTcpipForwardingFilter(new ForwardingFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean canForwardAgent(ServerSession session) {
|
public boolean canForwardAgent(Session session) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canForwardX11(ServerSession session) {
|
public boolean canForwardX11(Session session) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canConnect(InetSocketAddress address, ServerSession session) {
|
public boolean canListen(SshdSocketAddress address, Session session) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canListen(InetSocketAddress address, ServerSession session) {
|
public boolean canConnect(SshdSocketAddress address, Session session) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setTcpipForwarderFactory(new DefaultTcpipForwarderFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFileSystemFactory() {
|
private void initFileSystemFactory() {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import com.google.gerrit.server.IdentifiedUser;
|
|||||||
import com.google.gerrit.sshd.SshScope.Context;
|
import com.google.gerrit.sshd.SshScope.Context;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.mina.core.future.IoFuture;
|
import org.apache.sshd.common.future.CloseFuture;
|
||||||
import org.apache.mina.core.future.IoFutureListener;
|
import org.apache.sshd.common.future.SshFutureListener;
|
||||||
import org.apache.sshd.common.KeyPairProvider;
|
import org.apache.sshd.common.KeyPairProvider;
|
||||||
import org.apache.sshd.common.SshException;
|
import org.apache.sshd.common.SshException;
|
||||||
import org.apache.sshd.common.util.Buffer;
|
import org.apache.sshd.common.util.Buffer;
|
||||||
@@ -138,10 +138,11 @@ public class SshUtil {
|
|||||||
sshScope.set(old);
|
sshScope.set(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getIoSession().getCloseFuture().addListener(
|
GerritServerSession s = (GerritServerSession) session;
|
||||||
new IoFutureListener<IoFuture>() {
|
s.addCloseSessionListener(
|
||||||
|
new SshFutureListener<CloseFuture>() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(IoFuture future) {
|
public void operationComplete(CloseFuture future) {
|
||||||
final Context ctx = sshScope.newContext(null, sd, null);
|
final Context ctx = sshScope.newContext(null, sd, null);
|
||||||
final Context old = sshScope.set(ctx);
|
final Context old = sshScope.set(ctx);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -32,8 +32,9 @@ import com.google.gerrit.sshd.SshDaemon;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
import org.apache.mina.core.service.IoAcceptor;
|
import org.apache.sshd.common.io.IoAcceptor;
|
||||||
import org.apache.mina.core.session.IoSession;
|
import org.apache.sshd.common.io.IoSession;
|
||||||
|
import org.apache.sshd.common.io.mina.MinaSession;
|
||||||
import org.apache.sshd.server.Environment;
|
import org.apache.sshd.server.Environment;
|
||||||
import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor;
|
import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
@@ -274,8 +275,12 @@ final class ShowCaches extends CacheCommand {
|
|||||||
long now = TimeUtil.nowMs();
|
long now = TimeUtil.nowMs();
|
||||||
Collection<IoSession> list = acceptor.getManagedSessions().values();
|
Collection<IoSession> list = acceptor.getManagedSessions().values();
|
||||||
long oldest = now;
|
long oldest = now;
|
||||||
|
|
||||||
for (IoSession s : list) {
|
for (IoSession s : list) {
|
||||||
oldest = Math.min(oldest, s.getCreationTime());
|
if (s instanceof MinaSession) {
|
||||||
|
MinaSession minaSession = (MinaSession)s;
|
||||||
|
oldest = Math.min(oldest, minaSession.getSession().getCreationTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.format(
|
stdout.format(
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ import com.google.gerrit.sshd.SshDaemon;
|
|||||||
import com.google.gerrit.sshd.SshSession;
|
import com.google.gerrit.sshd.SshSession;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.apache.mina.core.service.IoAcceptor;
|
import org.apache.sshd.common.io.IoAcceptor;
|
||||||
import org.apache.mina.core.session.IoSession;
|
import org.apache.sshd.common.io.IoSession;
|
||||||
|
import org.apache.sshd.common.io.mina.MinaSession;
|
||||||
import org.apache.sshd.server.Environment;
|
import org.apache.sshd.server.Environment;
|
||||||
import org.apache.sshd.server.session.ServerSession;
|
import org.apache.sshd.server.session.ServerSession;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
@@ -84,11 +85,17 @@ final class ShowConnections extends SshCommand {
|
|||||||
Collections.sort(list, new Comparator<IoSession>() {
|
Collections.sort(list, new Comparator<IoSession>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(IoSession arg0, IoSession arg1) {
|
public int compare(IoSession arg0, IoSession arg1) {
|
||||||
if (arg0.getCreationTime() < arg1.getCreationTime()) {
|
if (arg0 instanceof MinaSession) {
|
||||||
|
MinaSession mArg0 = (MinaSession) arg0;
|
||||||
|
MinaSession mArg1 = (MinaSession) arg1;
|
||||||
|
if (mArg0.getSession().getCreationTime() < mArg1.getSession()
|
||||||
|
.getCreationTime()) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (arg0.getCreationTime() > arg1.getCreationTime()) {
|
} else if (mArg0.getSession().getCreationTime() > mArg1.getSession()
|
||||||
|
.getCreationTime()) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return (int) (arg0.getId() - arg1.getId());
|
return (int) (arg0.getId() - arg1.getId());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -104,8 +111,15 @@ final class ShowConnections extends SshCommand {
|
|||||||
SshSession sd = s != null ? s.getAttribute(SshSession.KEY) : null;
|
SshSession sd = s != null ? s.getAttribute(SshSession.KEY) : null;
|
||||||
|
|
||||||
final SocketAddress remoteAddress = io.getRemoteAddress();
|
final SocketAddress remoteAddress = io.getRemoteAddress();
|
||||||
final long start = io.getCreationTime();
|
MinaSession minaSession = io instanceof MinaSession
|
||||||
final long idle = now - io.getLastIoTime();
|
? (MinaSession) io
|
||||||
|
: null;
|
||||||
|
final long start = minaSession == null
|
||||||
|
? 0
|
||||||
|
: minaSession.getSession().getCreationTime();
|
||||||
|
final long idle = minaSession == null
|
||||||
|
? now
|
||||||
|
: now - minaSession.getSession().getLastIoTime();
|
||||||
|
|
||||||
stdout.print(String.format("%8s %8s %8s %-15.15s %s\n", //
|
stdout.print(String.format("%8s %8s %8s %-15.15s %s\n", //
|
||||||
id(sd), //
|
id(sd), //
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ log4j.logger.org.apache.mina=WARN
|
|||||||
log4j.logger.org.apache.sshd.common=WARN
|
log4j.logger.org.apache.sshd.common=WARN
|
||||||
log4j.logger.org.apache.sshd.server=WARN
|
log4j.logger.org.apache.sshd.server=WARN
|
||||||
log4j.logger.org.apache.sshd.common.keyprovider.FileKeyPairProvider=INFO
|
log4j.logger.org.apache.sshd.common.keyprovider.FileKeyPairProvider=INFO
|
||||||
log4j.logger.com.google.gerrit.server.ssh.GerritServerSession=WARN
|
log4j.logger.com.google.gerrit.sshd.GerritServerSession=WARN
|
||||||
|
|
||||||
# Silence non-critical messages from Jetty.
|
# Silence non-critical messages from Jetty.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -8,17 +8,18 @@ EXCLUDE = [
|
|||||||
|
|
||||||
maven_jar(
|
maven_jar(
|
||||||
name = 'core',
|
name = 'core',
|
||||||
id = 'org.apache.mina:mina-core:2.0.5',
|
id = 'org.apache.mina:mina-core:2.0.7',
|
||||||
sha1 = '0e134a3761833a3c28c79331e806f64f985a9eec',
|
sha1 = 'c878e2aa82de748474a624ec3933e4604e446dec',
|
||||||
license = 'Apache2.0',
|
license = 'Apache2.0',
|
||||||
exclude = EXCLUDE,
|
exclude = EXCLUDE,
|
||||||
)
|
)
|
||||||
|
|
||||||
maven_jar(
|
maven_jar(
|
||||||
name = 'sshd',
|
name = 'sshd',
|
||||||
id = 'org.apache.sshd:sshd-core:0.6.0',
|
id = 'org.apache.sshd:sshd-core:0.9.0.201311081',
|
||||||
sha1 = '2b9a119dd77a1decec78b0c511ba400c8655e96e',
|
sha1 = '38f7ac8602e70fa05fdc6147d204198e9cefe5bc',
|
||||||
license = 'Apache2.0',
|
license = 'Apache2.0',
|
||||||
deps = [':core'],
|
deps = [':core'],
|
||||||
exclude = EXCLUDE,
|
exclude = EXCLUDE,
|
||||||
|
repository = GERRIT,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user