Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/release' into integration/master
Browse files Browse the repository at this point in the history
Conflicts:
	functional-test/pom.xml
	pom.xml
	zanata-model/pom.xml
	zanata-war/pom.xml
	zanata-war/src/main/java/org/zanata/async/AsynchronousTaskExecutor.java
	zanata-war/src/main/java/org/zanata/async/TaskExecutor.java
	zanata-war/src/main/java/org/zanata/service/impl/AsyncTaskManagerServiceImpl.java
	zanata-war/src/main/resources/messages_en_GB.properties
	zanata-war/src/main/resources/messages_ja.properties
	zanata-war/src/main/resources/messages_uk.properties
	zanata-war/src/main/resources/messages_zh_TW_Hant.properties
	zanata-war/src/main/webapp/WEB-INF/pages.xml
	zanata-war/src/main/webapp/admin/processmanager.xhtml
  • Loading branch information
Carlos A. Munoz committed Jul 23, 2014
2 parents 1a10a89 + ebcc32a commit 19bd165
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 68 deletions.
Expand Up @@ -70,10 +70,6 @@ public Date getDateFromLong(long value) {
return new Date(value);
}

public void clearAllFinished() {
asyncTaskManagerServiceImpl.clearInactive();
}

public void cancel(AsyncTaskHandle handle) {
handle.cancel();
}
Expand Down
Expand Up @@ -24,6 +24,7 @@

import javax.security.auth.Subject;

import com.google.common.util.concurrent.MoreExecutors;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.Name;
Expand Down Expand Up @@ -64,7 +65,8 @@ public class AsynchronousTaskExecutor {
*/
@Asynchronous
public <V, H extends AsyncTaskHandle<V>> void runAsynchronously(
final AsyncTask<V, H> task, final Principal runAsPpal,
final AsyncTask<V, H> task, final Runnable onComplete,
final Principal runAsPpal,
final Subject runAsSubject, final String username) {
AsyncUtils.outject(task.getHandle(), ScopeType.EVENT);

Expand All @@ -75,11 +77,12 @@ public void execute() {
prepareSecurityContext(username);
V returnValue = task.call();
task.getHandle().set(returnValue);
} catch (Exception t) {
} catch (Throwable t) {
task.getHandle().setException(t);
log.error(
"Exception when executing an asynchronous task.", t);
}
onComplete.run();
}

@Override
Expand All @@ -92,7 +95,6 @@ public Subject getSubject() {
return runAsSubject;
}
};

runAsOp.run();
}

Expand Down
5 changes: 3 additions & 2 deletions zanata-war/src/main/java/org/zanata/async/TaskExecutor.java
Expand Up @@ -50,15 +50,16 @@ public class TaskExecutor {
*
* @param task
* The task to execute.
* @param onComplete
* @return The task handle to keep track of the executed task.
* @throws RuntimeException
* If the provided task value is null.
*/
public <V, H extends AsyncTaskHandle<V>> AsyncTaskHandle<V> startTask(
@Nonnull AsyncTask<V, H> task) {
@Nonnull AsyncTask<V, H> task, Runnable onComplete) {
H handle = task.getHandle();
Identity identity = Identity.instance();
asynchronousTaskExecutor.runAsynchronously(task, identity
asynchronousTaskExecutor.runAsynchronously(task, onComplete, identity
.getPrincipal(), identity.getSubject(),
identity.getCredentials().getUsername());
return handle;
Expand Down
Expand Up @@ -83,10 +83,4 @@ <V, H extends AsyncTaskHandle<V>> void startTask(AsyncTask<V, H> task,
*/
Collection<AsyncTaskHandle> getAllHandles();

/**
* Clears all the inactive handles managed by this service. Inactive handles
* all all those handles that reference a task that is either finished, has
* encountered an error, or has been cancelled.
*/
void clearInactive();
}
Expand Up @@ -22,7 +22,9 @@

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
Expand All @@ -36,7 +38,6 @@
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

/**
Expand All @@ -50,71 +51,115 @@
@Name("asyncTaskManagerServiceImpl")
@Scope(ScopeType.APPLICATION)
@Startup
@Slf4j
public class AsyncTaskManagerServiceImpl implements AsyncTaskManagerService {

// Collection of all managed task Handles. It's self pruned, and it is
// indexed by
// long valued keys
private Cache<Long, AsyncTaskHandle> handlesById = CacheBuilder
.newBuilder().softValues().expireAfterWrite(1, TimeUnit.HOURS)
.build();
// Map of all active task handles
private Map<Serializable, AsyncTaskHandle> handlesByKey = Maps.newConcurrentMap();

private ConcurrentMap<Serializable, AsyncTaskHandle> handlesByKey = Maps
.newConcurrentMap();
// Cache of recently completed tasks
private Cache<Serializable, AsyncTaskHandle> finishedTasks = CacheBuilder
.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
.build();

private long lastAssignedKey = 1;

/**
* Starts a task, using a generated task key
* @param task
* The asynchronous task to run.
* @param <V>
* @param <H>
* @return
*/
@Override
public <V, H extends AsyncTaskHandle<V>> String startTask(
AsyncTask<V, H> task) {
TaskExecutor taskExecutor =
ServiceLocator.instance().getInstance(TaskExecutor.class);
AsyncTaskHandle<V> handle = taskExecutor.startTask(task);
Long taskKey;
taskKey = generateNextAvailableKey();
handlesById.put(taskKey, handle);
Long taskKey = generateNextAvailableKey();
startTask(task, taskKey);
return taskKey.toString();
}

/**
* Starts a task, using the specified task key
* @param task
* The asynchronous task to run.
* @param key
* @param <V>
* @param <H>
*/
@Override
public <V, H extends AsyncTaskHandle<V>> void startTask(
AsyncTask<V, H> task, Serializable key) {
String taskId = startTask(task);
handlesByKey.put(key, getHandle(taskId));
AsyncTask<V, H> task, final Serializable key) {
TaskExecutor taskExecutor =
ServiceLocator.instance().getInstance(TaskExecutor.class);
AsyncTaskHandle<V> handle = taskExecutor.startTask(task,
new Runnable() {
@Override
public void run() {
taskFinished(key);
}
});
AsyncTaskHandle oldHandle = handlesByKey.put(key, handle);
if (oldHandle != null) {
log.error(
"Key {} has a duplicate: old handle is {}; new handle is {}",
key, oldHandle, handle);
}
}

private void taskFinished(Serializable key) {
AsyncTaskHandle handle = handlesByKey.remove(key);
if (handle != null) {
finishedTasks.put(key, handle);
} else {
log.error("unknown task key: {}", key);
}
}

/**
* Gets the handle for a generated task key
* @param taskId
* The task Id (as returned by
* {@link AsyncTaskManagerService#startTask(org.zanata.async.AsyncTask)}
* )
* @return
*/
@Override
public AsyncTaskHandle getHandle(String taskId) {
try {
Long taskKey = Long.parseLong(taskId);
AsyncTaskHandle handle = handlesById.getIfPresent(taskKey);
return handle;
return getHandleByKey(taskKey);
} catch (NumberFormatException e) {
return null; // Non-number keys are not allowed in this
// implementation
}
}

/**
* Gets the handle for a task which was started with a specified key
* @param key
* The task id as provided to
* {@link AsyncTaskManagerService#startTask(org.zanata.async.AsyncTask, java.io.Serializable)}
* @return
*/
@Override
public AsyncTaskHandle getHandleByKey(Serializable key) {
return handlesByKey.get(key);
}

@Override
public void clearInactive() {
synchronized (handlesById) {
for (Map.Entry<Long, AsyncTaskHandle> entry : handlesById.asMap()
.entrySet()) {
if (entry.getValue().isDone()) {
handlesById.invalidate(entry.getKey());
}
}
// NB: check the active tasks before finished tasks, in
// case the task finishes in between
AsyncTaskHandle handle = handlesByKey.get(key);
if (handle == null) {
handle = finishedTasks.getIfPresent(key);
}
return handle;
}

@Override
public Collection<AsyncTaskHandle> getAllHandles() {
return handlesById.asMap().values();
Collection<AsyncTaskHandle> handles = Lists.newArrayList();
handles.addAll(handlesByKey.values());
handles.addAll(finishedTasks.asMap().values());
return handles;
}

private synchronized long generateNextAvailableKey() {
Expand Down
Expand Up @@ -59,6 +59,7 @@ public class Application implements EntryPoint {
private UncaughtExceptionHandlerImpl exceptionHandler;

public void onModuleLoad() {
Log.info("Loading Zanata Web Editor...");
exceptionHandler =
new UncaughtExceptionHandlerImpl(injector.getDispatcher(),
injector.getUserConfig());
Expand All @@ -71,6 +72,7 @@ public void onModuleLoad() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof AuthenticationError) {
Log.error("Authentication error.", caught);
redirectToLogin();
} else if (caught instanceof NoSuchWorkspaceException) {
Log.error("Invalid workspace", caught);
Expand Down
Expand Up @@ -7,6 +7,7 @@
import org.zanata.webtrans.client.Application;
import org.zanata.webtrans.client.events.NotificationEvent;
import org.zanata.webtrans.client.resources.RpcMessages;
import org.zanata.webtrans.client.util.JavascriptUtil;
import org.zanata.webtrans.shared.DispatchService;
import org.zanata.webtrans.shared.DispatchServiceAsync;
import org.zanata.webtrans.shared.auth.AuthenticationError;
Expand Down Expand Up @@ -65,7 +66,7 @@ public <A extends Action<R>, R extends Result> void execute(final A action,
.getWorkspaceId());
}

String sessionId = Cookies.getCookie("JSESSIONID");
final String sessionId = getSessionId();
realService.execute(new WrappedAction<R>(action, sessionId),
new AbstractAsyncCallback<Result>() {

Expand All @@ -79,8 +80,11 @@ public void onFailure(final Throwable caught) {
messages.noResponseFromServer()));
}
}
if (caught instanceof AuthenticationError
|| caught instanceof InvalidTokenError) {
if (caught instanceof AuthenticationError) {
Log.error("Authentication error.", caught);
Application.redirectToLogin();
} else if (caught instanceof InvalidTokenError) {
Log.error("Invalid Token error ("+ sessionId + ")", caught);
Application.redirectToLogin();
} else if (caught instanceof AuthorizationError) {
Log.info("RCP Authorization Error calling "
Expand All @@ -99,6 +103,10 @@ public void onSuccess(final Result result) {
});
}

private String getSessionId() {
return JavascriptUtil.getJavascriptValue("zanataSessionId");
}

@Override
public void setUserWorkspaceContext(
UserWorkspaceContext userWorkspaceContext) {
Expand Down Expand Up @@ -131,12 +139,13 @@ public <A extends Action<R>, R extends Result> void rollback(
.getWorkspaceId());
}

String sessionId = Cookies.getCookie("JSESSIONID");
String sessionId = getSessionId();
realService.rollback(new WrappedAction<R>(action, sessionId), result,
new AsyncCallback<Void>() {

public void onFailure(final Throwable caught) {
if (caught instanceof AuthenticationError) {
Log.error("Authentication error.");
Application.redirectToLogin();
} else if (caught instanceof AuthorizationError) {
Log.info("RCP Authorization Error calling "
Expand Down
@@ -0,0 +1,39 @@
/*
* Copyright 2014, Red Hat, Inc. and individual contributors as indicated by the
* @author tags. See the copyright.txt file in the distribution for a full
* listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
* site: http://www.fsf.org.
*/
package org.zanata.webtrans.client.util;

/**
* Utilities for dealing with javascript native code.
*
* @author Carlos Munoz <a
* href="mailto:camunoz@redhat.com">camunoz@redhat.com</a>
*/
public class JavascriptUtil {
/**
* Returns the value of a variable declared in javascript at the window
* level.
* @param varName Variable name.
* @return The value (as a string) assigned to varName.
*/
public static native String getJavascriptValue(String varName) /*-{
return $wnd[varName];
}-*/;
}
Expand Up @@ -127,6 +127,8 @@ public <A extends Action<R>, R extends Result> R execute(A action)
HttpSession session =
ServletContexts.instance().getRequest().getSession();
if (session != null && !session.getId().equals(a.getCsrfToken())) {
log.warn("Token mismatch. Client token: {}, Expected token: {}",
a.getCsrfToken(), session.getId());
throw new InvalidTokenError(
"The csrf token sent with this request is not valid. It may be from an expired session, or may have been forged");
}
Expand Down
1 change: 0 additions & 1 deletion zanata-war/src/main/resources/messages.properties
Expand Up @@ -951,7 +951,6 @@ jsf.rolerules.RoleToAssign.tooltip=This is the role that will be automatically a


#------ [home] > Administration > Process Manager ------
jsf.processmanager.ClearAllFinished.label=Clear All Finished
jsf.processmanager.TotalRunning=Total Running
jsf.processmanager.TotalFinished=Total Finished
! type of process that is currently running
Expand Down
Expand Up @@ -51,6 +51,9 @@
<!-- to create a completely dynamic UI. -->
<!-- -->
<body class="new-zanata-body">
<script type="text/javascript">
var zanataSessionId = '#{request.session.id}';
</script>
<div class="new-zanata-base">
<div class="new-zanata">
<ui:include src="../WEB-INF/template/banner.xhtml"/>
Expand Down
4 changes: 0 additions & 4 deletions zanata-war/src/main/webapp/WEB-INF/pages.xml
Expand Up @@ -390,10 +390,6 @@
execute="#{breadcrumbs.addLocation('/admin/home.xhtml', msgs['jsf.Administration'])}" />
<action
execute="#{breadcrumbs.addLocation('/admin/processmanager.xhtml', msgs['jsf.ProcessManager'])}" />

<navigation from-action="#{processManagerAction.clearAllFinished}">
<redirect view-id="/admin/processmanager.xhtml" />
</navigation>
</page>

<!-- Version Group -->
Expand Down

0 comments on commit 19bd165

Please sign in to comment.