fix exam config defaults, code cleanup
This commit is contained in:
parent
e7af727854
commit
a076c62d46
46 changed files with 6878 additions and 6957 deletions
|
@ -82,8 +82,8 @@ public class ResourceService {
|
||||||
|
|
||||||
private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING";
|
private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING";
|
||||||
|
|
||||||
public static final Comparator<Tuple<String>> RESOURCE_COMPARATOR = (t1, t2) -> t1._2.compareTo(t2._2);
|
public static final Comparator<Tuple<String>> RESOURCE_COMPARATOR = Comparator.comparing(t -> t._2);
|
||||||
public static final Comparator<Tuple3<String>> RESOURCE_COMPARATOR_TUPLE_3 = (t1, t2) -> t1._2.compareTo(t2._2);
|
public static final Comparator<Tuple3<String>> RESOURCE_COMPARATOR_TUPLE_3 = Comparator.comparing(t -> t._2);
|
||||||
|
|
||||||
public static final EnumSet<EntityType> ENTITY_TYPE_EXCLUDE_MAP = EnumSet.of(
|
public static final EnumSet<EntityType> ENTITY_TYPE_EXCLUDE_MAP = EnumSet.of(
|
||||||
EntityType.ADDITIONAL_ATTRIBUTES,
|
EntityType.ADDITIONAL_ATTRIBUTES,
|
||||||
|
|
|
@ -1,50 +1,50 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page;
|
package ch.ethz.seb.sebserver.gui.service.page;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
|
||||||
public class FieldValidationError {
|
public class FieldValidationError {
|
||||||
|
|
||||||
public final String messageCode;
|
public final String messageCode;
|
||||||
public final String domainName;
|
public final String domainName;
|
||||||
public final String fieldName;
|
public final String fieldName;
|
||||||
public final String errorType;
|
public final String errorType;
|
||||||
public final Collection<String> attributes;
|
public final Collection<String> attributes;
|
||||||
|
|
||||||
public FieldValidationError(final APIMessage apiMessage) {
|
public FieldValidationError(final APIMessage apiMessage) {
|
||||||
this(
|
this(
|
||||||
apiMessage.messageCode,
|
apiMessage.messageCode,
|
||||||
apiMessage.attributes.toArray(new String[apiMessage.attributes.size()]));
|
apiMessage.attributes.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldValidationError(
|
public FieldValidationError(
|
||||||
final String messageCode,
|
final String messageCode,
|
||||||
final String[] attributes) {
|
final String[] attributes) {
|
||||||
|
|
||||||
this.messageCode = messageCode;
|
this.messageCode = messageCode;
|
||||||
this.attributes = Utils.immutableCollectionOf(attributes);
|
this.attributes = Utils.immutableCollectionOf(attributes);
|
||||||
|
|
||||||
this.domainName = (attributes != null && attributes.length > 0) ? attributes[0] : null;
|
this.domainName = (attributes != null && attributes.length > 0) ? attributes[0] : null;
|
||||||
this.fieldName = (attributes != null && attributes.length > 1) ? attributes[1] : null;
|
this.fieldName = (attributes != null && attributes.length > 1) ? attributes[1] : null;
|
||||||
this.errorType = (attributes != null && attributes.length > 2) ? attributes[2] : null;
|
this.errorType = (attributes != null && attributes.length > 2) ? attributes[2] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getAttributes() {
|
public String[] getAttributes() {
|
||||||
if (this.attributes == null) {
|
if (this.attributes == null) {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.attributes.toArray(new String[this.attributes.size()]);
|
return this.attributes.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,292 +1,292 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page;
|
package ch.ethz.seb.sebserver.gui.service.page;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
|
|
||||||
/** Holds a page-context and defines some convenient functionality for page handling */
|
/** Holds a page-context and defines some convenient functionality for page handling */
|
||||||
public interface PageContext {
|
public interface PageContext {
|
||||||
|
|
||||||
Logger log = LoggerFactory.getLogger(PageContext.class);
|
Logger log = LoggerFactory.getLogger(PageContext.class);
|
||||||
|
|
||||||
/** Defines attribute keys that can be used to store attribute values within the page context state */
|
/** Defines attribute keys that can be used to store attribute values within the page context state */
|
||||||
public interface AttributeKeys {
|
interface AttributeKeys {
|
||||||
|
|
||||||
public static final String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
|
String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
|
||||||
|
|
||||||
public static final String READ_ONLY = "READ_ONLY";
|
String READ_ONLY = "READ_ONLY";
|
||||||
public static final String READ_ONLY_FROM = "READ_ONLY_FROM";
|
String READ_ONLY_FROM = "READ_ONLY_FROM";
|
||||||
|
|
||||||
public static final String ENTITY_ID = "ENTITY_ID";
|
String ENTITY_ID = "ENTITY_ID";
|
||||||
public static final String PARENT_ENTITY_ID = "PARENT_ENTITY_ID";
|
String PARENT_ENTITY_ID = "PARENT_ENTITY_ID";
|
||||||
public static final String ENTITY_TYPE = "ENTITY_TYPE";
|
String ENTITY_TYPE = "ENTITY_TYPE";
|
||||||
public static final String PARENT_ENTITY_TYPE = "PARENT_ENTITY_TYPE";
|
String PARENT_ENTITY_TYPE = "PARENT_ENTITY_TYPE";
|
||||||
|
|
||||||
public static final String IMPORT_FROM_QUIZ_DATA = "IMPORT_FROM_QUIZ_DATA";
|
String IMPORT_FROM_QUIZ_DATA = "IMPORT_FROM_QUIZ_DATA";
|
||||||
|
|
||||||
public static final String COPY_AS_TEMPLATE = "COPY_AS_TEMPLATE";
|
String COPY_AS_TEMPLATE = "COPY_AS_TEMPLATE";
|
||||||
public static final String CREATE_FROM_TEMPLATE = "CREATE_FROM_TEMPLATE";
|
String CREATE_FROM_TEMPLATE = "CREATE_FROM_TEMPLATE";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The resource-bundle key of the generic load entity error message. */
|
/** The resource-bundle key of the generic load entity error message. */
|
||||||
public static final String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity";
|
String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity";
|
||||||
public static final String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity";
|
String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity";
|
||||||
public static final String GENERIC_SAVE_ERROR_TEXT_KEY = "sebserver.error.save.entity";
|
String GENERIC_SAVE_ERROR_TEXT_KEY = "sebserver.error.save.entity";
|
||||||
public static final String GENERIC_ACTIVATE_ERROR_TEXT_KEY = "sebserver.error.activate.entity";
|
String GENERIC_ACTIVATE_ERROR_TEXT_KEY = "sebserver.error.activate.entity";
|
||||||
public static final String GENERIC_IMPORT_ERROR_TEXT_KEY = "sebserver.error.import";
|
String GENERIC_IMPORT_ERROR_TEXT_KEY = "sebserver.error.import";
|
||||||
public static final LocTextKey SUCCESS_MSG_TITLE =
|
LocTextKey SUCCESS_MSG_TITLE =
|
||||||
new LocTextKey("sebserver.page.message");
|
new LocTextKey("sebserver.page.message");
|
||||||
public static final LocTextKey UNEXPECTED_ERROR_KEY =
|
LocTextKey UNEXPECTED_ERROR_KEY =
|
||||||
new LocTextKey("sebserver.error.action.unexpected.message");
|
new LocTextKey("sebserver.error.action.unexpected.message");
|
||||||
|
|
||||||
/** Get the I18nSupport service
|
/** Get the I18nSupport service
|
||||||
*
|
*
|
||||||
* @return the I18nSupport service */
|
* @return the I18nSupport service */
|
||||||
I18nSupport getI18nSupport();
|
I18nSupport getI18nSupport();
|
||||||
|
|
||||||
/** Use this to get the ComposerService used by this PageContext
|
/** Use this to get the ComposerService used by this PageContext
|
||||||
*
|
*
|
||||||
* @return the ComposerService used by this PageContext */
|
* @return the ComposerService used by this PageContext */
|
||||||
ComposerService composerService();
|
ComposerService composerService();
|
||||||
|
|
||||||
/** Get the RWT Shell that is bound within this PageContext
|
/** Get the RWT Shell that is bound within this PageContext
|
||||||
*
|
*
|
||||||
* @return the RWT Shell that is bound within this PageContext */
|
* @return the RWT Shell that is bound within this PageContext */
|
||||||
Shell getShell();
|
Shell getShell();
|
||||||
|
|
||||||
/** Get the page root Component.
|
/** Get the page root Component.
|
||||||
*
|
*
|
||||||
* @return the page root Component. */
|
* @return the page root Component. */
|
||||||
Composite getRoot();
|
Composite getRoot();
|
||||||
|
|
||||||
/** Get the Component that is currently set as parent during page tree compose
|
/** Get the Component that is currently set as parent during page tree compose
|
||||||
*
|
*
|
||||||
* @return the parent Component */
|
* @return the parent Component */
|
||||||
Composite getParent();
|
Composite getParent();
|
||||||
|
|
||||||
/** Get a copy of this PageContext.
|
/** Get a copy of this PageContext.
|
||||||
*
|
*
|
||||||
* @return */
|
* @return a deep copy of this PageContext */
|
||||||
PageContext copy();
|
PageContext copy();
|
||||||
|
|
||||||
/** Create a copy of this PageContext with a new parent Composite.
|
/** Create a copy of this PageContext with a new parent Composite.
|
||||||
* The implementation should take care of the imutability of PageContext and return a copy with the new parent
|
* The implementation should take care of the immutability of PageContext and return a copy with the new parent
|
||||||
* by leave this PageContext as is.
|
* by leave this PageContext as is.
|
||||||
*
|
*
|
||||||
* @param parent the new parent Composite
|
* @param parent the new parent Composite
|
||||||
* @return a copy of this PageContext with a new parent Composite. */
|
* @return a copy of this PageContext with a new parent Composite. */
|
||||||
PageContext copyOf(Composite parent);
|
PageContext copyOf(Composite parent);
|
||||||
|
|
||||||
/** Create a copy of this PageContext with and additionally page context attributes.
|
/** Create a copy of this PageContext with and additionally page context attributes.
|
||||||
* The additionally page context attributes will get merged with them already defined
|
* The additionally page context attributes will get merged with them already defined
|
||||||
* The implementation should take care of the imutability of PageContext and return a copy with the merge
|
* The implementation should take care of the immutability of PageContext and return a copy with the merge
|
||||||
* by leave this and the given PageContext as is.
|
* by leave this and the given PageContext as is.
|
||||||
*
|
*
|
||||||
* @param attributes additionally page context attributes.
|
* @param otherContext the other PageContext to copy the attributes from
|
||||||
* @return a copy of this PageContext with with and additionally page context attributes. */
|
* @return a copy of this PageContext with with and additionally page context attributes. */
|
||||||
PageContext copyOfAttributes(PageContext otherContext);
|
PageContext copyOfAttributes(PageContext otherContext);
|
||||||
|
|
||||||
/** Adds the specified attribute to the existing page context attributes.
|
/** Adds the specified attribute to the existing page context attributes.
|
||||||
* The implementation should take care of the imutability of PageContext and return a copy
|
* The implementation should take care of the immutability of PageContext and return a copy
|
||||||
* by leave this PageContext as is.
|
* by leave this PageContext as is.
|
||||||
*
|
*
|
||||||
* @param key the key of the attribute
|
* @param key the key of the attribute
|
||||||
* @param value the value of the attribute
|
* @param value the value of the attribute
|
||||||
* @return this PageContext instance (builder pattern) */
|
* @return this PageContext instance (builder pattern) */
|
||||||
PageContext withAttribute(String key, String value);
|
PageContext withAttribute(String key, String value);
|
||||||
|
|
||||||
/** Gets a copy of this PageContext with cleared attribute map.
|
/** Gets a copy of this PageContext with cleared attribute map.
|
||||||
*
|
*
|
||||||
* @return a copy of this PageContext with cleared attribute map. */
|
* @return a copy of this PageContext with cleared attribute map. */
|
||||||
PageContext clearAttributes();
|
PageContext clearAttributes();
|
||||||
|
|
||||||
/** Get the attribute value that is mapped to the given name or null of no mapping exists
|
/** Get the attribute value that is mapped to the given name or null of no mapping exists
|
||||||
*
|
*
|
||||||
* @param name the attribute name
|
* @param name the attribute name
|
||||||
* @return the attribute value that is mapped to the given name or null if no mapping exists */
|
* @return the attribute value that is mapped to the given name or null if no mapping exists */
|
||||||
String getAttribute(String name);
|
String getAttribute(String name);
|
||||||
|
|
||||||
/** Get the attribute value that is mapped to the given name or a default value if no mapping exists
|
/** Get the attribute value that is mapped to the given name or a default value if no mapping exists
|
||||||
*
|
*
|
||||||
* @param name the attribute name
|
* @param name the attribute name
|
||||||
* @param def the default value
|
* @param def the default value
|
||||||
* @return the attribute value that is mapped to the given name or null of no mapping exists */
|
* @return the attribute value that is mapped to the given name or null of no mapping exists */
|
||||||
String getAttribute(String name, String def);
|
String getAttribute(String name, String def);
|
||||||
|
|
||||||
/** Indicates if the attribute with the key READ_ONLY is set to true within this PageContext
|
/** Indicates if the attribute with the key READ_ONLY is set to true within this PageContext
|
||||||
*
|
*
|
||||||
* @return true if the attribute with the key READ_ONLY is set to true */
|
* @return true if the attribute with the key READ_ONLY is set to true */
|
||||||
boolean isReadonly();
|
boolean isReadonly();
|
||||||
|
|
||||||
/** Gets an EntityKey for the base Entity that is associated within this PageContext by using
|
/** Gets an EntityKey for the base Entity that is associated within this PageContext by using
|
||||||
* the attribute keys ENTITY_ID and ENTITY_TYPE to fetch the attribute values for an EntityKey
|
* the attribute keys ENTITY_ID and ENTITY_TYPE to fetch the attribute values for an EntityKey
|
||||||
*
|
*
|
||||||
* @return the EntityKey of the base Entity that is associated within this PageContext */
|
* @return the EntityKey of the base Entity that is associated within this PageContext */
|
||||||
EntityKey getEntityKey();
|
EntityKey getEntityKey();
|
||||||
|
|
||||||
/** Gets an EntityKey for the parent Entity that is associated within this PageContext by using
|
/** Gets an EntityKey for the parent Entity that is associated within this PageContext by using
|
||||||
* the attribute keys PARENT_ENTITY_ID and PARENT_ENTITY_TYPE to fetch the attribute values for an EntityKey
|
* the attribute keys PARENT_ENTITY_ID and PARENT_ENTITY_TYPE to fetch the attribute values for an EntityKey
|
||||||
*
|
*
|
||||||
* @return the EntityKey of the parent Entity that is associated within this PageContext */
|
* @return the EntityKey of the parent Entity that is associated within this PageContext */
|
||||||
EntityKey getParentEntityKey();
|
EntityKey getParentEntityKey();
|
||||||
|
|
||||||
/** Adds a given EntityKey as base Entity key to a new PageContext that is returned as a copy of this PageContext.
|
/** Adds a given EntityKey as base Entity key to a new PageContext that is returned as a copy of this PageContext.
|
||||||
*
|
*
|
||||||
* @param entityKey the EntityKey to add as base Entity key
|
* @param entityKey the EntityKey to add as base Entity key
|
||||||
* @return the new PageContext with the EntityKey added */
|
* @return the new PageContext with the EntityKey added */
|
||||||
PageContext withEntityKey(EntityKey entityKey);
|
PageContext withEntityKey(EntityKey entityKey);
|
||||||
|
|
||||||
/** Adds a given EntityKey as parent Entity key to a new PageContext that is returned as a copy of this PageContext.
|
/** Adds a given EntityKey as parent Entity key to a new PageContext that is returned as a copy of this PageContext.
|
||||||
*
|
*
|
||||||
* @param entityKey the EntityKey to add as parent Entity key
|
* @param entityKey the EntityKey to add as parent Entity key
|
||||||
* @return the new PageContext with the EntityKey added */
|
* @return the new PageContext with the EntityKey added */
|
||||||
PageContext withParentEntityKey(EntityKey entityKey);
|
PageContext withParentEntityKey(EntityKey entityKey);
|
||||||
|
|
||||||
/** Create a copy of this PageContext and resets both entity keys attributes, the base and the parent EntityKey
|
/** Create a copy of this PageContext and resets both entity keys attributes, the base and the parent EntityKey
|
||||||
*
|
*
|
||||||
* @return copy of this PageContext with reseted EntityKey attributes (base and parent) */
|
* @return copy of this PageContext with reset EntityKey attributes (base and parent) */
|
||||||
PageContext clearEntityKeys();
|
PageContext clearEntityKeys();
|
||||||
|
|
||||||
/** Indicates if an attribute with the specified name exists within this PageContext
|
/** Indicates if an attribute with the specified name exists within this PageContext
|
||||||
*
|
*
|
||||||
* @param name the name of the attribute
|
* @param name the name of the attribute
|
||||||
* @return true if the attribute with the specified name exists within this PageContext */
|
* @return true if the attribute with the specified name exists within this PageContext */
|
||||||
boolean hasAttribute(String name);
|
boolean hasAttribute(String name);
|
||||||
|
|
||||||
/** Returns a new PageContext with the removed attribute by name
|
/** Returns a new PageContext with the removed attribute by name
|
||||||
*
|
*
|
||||||
* @param name the name of the attribute to remove
|
* @param name the name of the attribute to remove
|
||||||
* @return a copy of this PageContext with the removed attribute */
|
* @return a copy of this PageContext with the removed attribute */
|
||||||
PageContext removeAttribute(String name);
|
PageContext removeAttribute(String name);
|
||||||
|
|
||||||
/** Apply a confirm dialog with a specified confirm message and a callback code
|
/** Apply a confirm dialog with a specified confirm message and a callback code
|
||||||
* block that will be executed on users OK selection.
|
* block that will be executed on users OK selection.
|
||||||
*
|
*
|
||||||
* @param confirmMessage the localized confirm message key
|
* @param confirmMessage the localized confirm message key
|
||||||
* @param onOK callback code block that will be called on users selection */
|
* @param callback callback code block that will be called on users selection */
|
||||||
void applyConfirmDialog(LocTextKey confirmMessage, final Consumer<Boolean> callback);
|
void applyConfirmDialog(LocTextKey confirmMessage, final Consumer<Boolean> callback);
|
||||||
|
|
||||||
/** This can be used to forward to a defined page.
|
/** This can be used to forward to a defined page.
|
||||||
*
|
*
|
||||||
* @param pageDefinition the defined page */
|
* @param pageDefinition the defined page */
|
||||||
void forwardToPage(PageDefinition pageDefinition);
|
void forwardToPage(PageDefinition pageDefinition);
|
||||||
|
|
||||||
/** Forward to main page */
|
/** Forward to main page */
|
||||||
void forwardToMainPage();
|
void forwardToMainPage();
|
||||||
|
|
||||||
/** Forward to login page */
|
/** Forward to login page */
|
||||||
void forwardToLoginPage();
|
void forwardToLoginPage();
|
||||||
|
|
||||||
/** Notify an error dialog to the user with specified error message and
|
/** Notify an error dialog to the user with specified error message and
|
||||||
* optional exception instance
|
* optional exception instance
|
||||||
*
|
*
|
||||||
* @param errorMessage the error message to display
|
* @param errorMessage the error message to display
|
||||||
* @param error the error as Exception */
|
* @param error the error as Exception */
|
||||||
void notifyError(LocTextKey errorMessage, Exception error);
|
void notifyError(LocTextKey errorMessage, Exception error);
|
||||||
|
|
||||||
/** Notify a generic load error to the user by pop-up
|
/** Notify a generic load error to the user by pop-up
|
||||||
*
|
*
|
||||||
* @param entityType the type of the entity
|
* @param entityType the type of the entity
|
||||||
* @param error the original error */
|
* @param error the original error */
|
||||||
default void notifyLoadError(final EntityType entityType, final Exception error) {
|
default void notifyLoadError(final EntityType entityType, final Exception error) {
|
||||||
notifyError(
|
notifyError(
|
||||||
new LocTextKey(
|
new LocTextKey(
|
||||||
GENERIC_LOAD_ERROR_TEXT_KEY,
|
GENERIC_LOAD_ERROR_TEXT_KEY,
|
||||||
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notify a generic remove error to the user by pop-up
|
/** Notify a generic remove error to the user by pop-up
|
||||||
*
|
*
|
||||||
* @param entityType the type of the entity
|
* @param entityType the type of the entity
|
||||||
* @param error the original error */
|
* @param error the original error */
|
||||||
default void notifyRemoveError(final EntityType entityType, final Exception error) {
|
default void notifyRemoveError(final EntityType entityType, final Exception error) {
|
||||||
notifyError(
|
notifyError(
|
||||||
new LocTextKey(
|
new LocTextKey(
|
||||||
GENERIC_REMOVE_ERROR_TEXT_KEY,
|
GENERIC_REMOVE_ERROR_TEXT_KEY,
|
||||||
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notify a generic save error to the user by pop-up
|
/** Notify a generic save error to the user by pop-up
|
||||||
*
|
*
|
||||||
* @param entityType the type of the entity
|
* @param entityType the type of the entity
|
||||||
* @param error the original error */
|
* @param error the original error */
|
||||||
default void notifySaveError(final EntityType entityType, final Exception error) {
|
default void notifySaveError(final EntityType entityType, final Exception error) {
|
||||||
notifyError(
|
notifyError(
|
||||||
new LocTextKey(
|
new LocTextKey(
|
||||||
GENERIC_SAVE_ERROR_TEXT_KEY,
|
GENERIC_SAVE_ERROR_TEXT_KEY,
|
||||||
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notify a generic activation error to the user by pop-up
|
/** Notify a generic activation error to the user by pop-up
|
||||||
*
|
*
|
||||||
* @param entityType the type of the entity
|
* @param entityType the type of the entity
|
||||||
* @param error the original error */
|
* @param error the original error */
|
||||||
default void notifyActivationError(final EntityType entityType, final Exception error) {
|
default void notifyActivationError(final EntityType entityType, final Exception error) {
|
||||||
notifyError(
|
notifyError(
|
||||||
new LocTextKey(
|
new LocTextKey(
|
||||||
GENERIC_ACTIVATE_ERROR_TEXT_KEY,
|
GENERIC_ACTIVATE_ERROR_TEXT_KEY,
|
||||||
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notify a generic import error to the user by pop-up
|
/** Notify a generic import error to the user by pop-up
|
||||||
*
|
*
|
||||||
* @param entityType the type of the entity
|
* @param entityType the type of the entity
|
||||||
* @param error the original error */
|
* @param error the original error */
|
||||||
default void notifyImportError(final EntityType entityType, final Exception error) {
|
default void notifyImportError(final EntityType entityType, final Exception error) {
|
||||||
notifyError(
|
notifyError(
|
||||||
new LocTextKey(
|
new LocTextKey(
|
||||||
GENERIC_IMPORT_ERROR_TEXT_KEY,
|
GENERIC_IMPORT_ERROR_TEXT_KEY,
|
||||||
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
getI18nSupport().getText(ResourceService.getEntityTypeNameKey(entityType))),
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notify a generic unexpected error to the user by pop-up
|
/** Notify a generic unexpected error to the user by pop-up
|
||||||
*
|
*
|
||||||
* @param error the original error */
|
* @param error the original error */
|
||||||
default void notifyUnexpectedError(final Exception error) {
|
default void notifyUnexpectedError(final Exception error) {
|
||||||
notifyError(UNEXPECTED_ERROR_KEY, error);
|
notifyError(UNEXPECTED_ERROR_KEY, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Publish and shows a message to the user with the given localized title and
|
/** Publish and shows a message to the user with the given localized title and
|
||||||
* localized message. The message text can also be HTML text as far as RWT supports it.
|
* localized message. The message text can also be HTML text as far as RWT supports it.
|
||||||
*
|
*
|
||||||
* @param title the localized text key of the title message
|
* @param title the localized text key of the title message
|
||||||
* @param message the localized text key of the message */
|
* @param message the localized text key of the message */
|
||||||
void publishPageMessage(LocTextKey title, LocTextKey message);
|
void publishPageMessage(LocTextKey title, LocTextKey message);
|
||||||
|
|
||||||
/** Publish an information message to the user with the given localized message.
|
/** Publish an information message to the user with the given localized message.
|
||||||
* The message text can also be HTML text as far as RWT supports it
|
* The message text can also be HTML text as far as RWT supports it
|
||||||
*
|
*
|
||||||
* @param message the localized text key of the message */
|
* @param message the localized text key of the message */
|
||||||
default void publishInfo(final LocTextKey message) {
|
default void publishInfo(final LocTextKey message) {
|
||||||
publishPageMessage(new LocTextKey("sebserver.page.message"), message);
|
publishPageMessage(new LocTextKey("sebserver.page.message"), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Publish and shows a formatted PageMessageException to the user.
|
/** Publish and shows a formatted PageMessageException to the user.
|
||||||
*
|
*
|
||||||
* @param pme the PageMessageException */
|
* @param pme the PageMessageException */
|
||||||
void publishPageMessage(PageMessageException pme);
|
void publishPageMessage(PageMessageException pme);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page;
|
package ch.ethz.seb.sebserver.gui.service.page;
|
||||||
|
|
||||||
public interface PageDefinition {
|
/** Defines a global SEB Server page */
|
||||||
|
public interface PageDefinition {
|
||||||
Class<? extends TemplateComposer> composer();
|
|
||||||
|
/** Get the type class of the TemplateComposer that composes the page.
|
||||||
PageContext applyPageContext(PageContext pageContext);
|
*
|
||||||
}
|
* @return the type class of the TemplateComposer that composes the page. */
|
||||||
|
Class<? extends TemplateComposer> composer();
|
||||||
|
|
||||||
|
PageContext applyPageContext(PageContext pageContext);
|
||||||
|
}
|
||||||
|
|
|
@ -363,7 +363,7 @@ public interface PageService {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used to update the crolledComposite when some if its content has dynamically changed
|
/** Used to update the scrolledComposite when some if its content has dynamically changed
|
||||||
* its dimensions.
|
* its dimensions.
|
||||||
*
|
*
|
||||||
* @param composite The Component that changed its dimensions */
|
* @param composite The Component that changed its dimensions */
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page;
|
package ch.ethz.seb.sebserver.gui.service.page;
|
||||||
|
|
||||||
public interface PageStateDefinition {
|
public interface PageStateDefinition {
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
LIST_VIEW,
|
LIST_VIEW,
|
||||||
FORM_VIEW,
|
FORM_VIEW,
|
||||||
FORM_EDIT,
|
FORM_EDIT,
|
||||||
FORM_IN_TIME_EDIT
|
FORM_IN_TIME_EDIT
|
||||||
}
|
}
|
||||||
|
|
||||||
String name();
|
String name();
|
||||||
|
|
||||||
Type type();
|
Type type();
|
||||||
|
|
||||||
public Class<? extends TemplateComposer> contentPaneComposer();
|
Class<? extends TemplateComposer> contentPaneComposer();
|
||||||
|
|
||||||
public Class<? extends TemplateComposer> actionPaneComposer();
|
Class<? extends TemplateComposer> actionPaneComposer();
|
||||||
|
|
||||||
Activity activityAnchor();
|
Activity activityAnchor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,27 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page;
|
package ch.ethz.seb.sebserver.gui.service.page;
|
||||||
|
|
||||||
public interface TemplateComposer {
|
/** interface defining a RAP page template composer */
|
||||||
|
public interface TemplateComposer {
|
||||||
default boolean validate(final PageContext pageContext) {
|
|
||||||
return true;
|
/** Validate given PageContext for completeness to compose a specific TemplateComposer implementation
|
||||||
}
|
* Default returns always true.
|
||||||
|
* @param pageContext The PageContext instance to check
|
||||||
void compose(PageContext pageContext);
|
* @return true if the PageContext contains all mandatory data to compose this page template */
|
||||||
|
default boolean validate(final PageContext pageContext) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compose a specific page template for the given PageContext
|
||||||
|
*
|
||||||
|
* @param pageContext The PageContext instance */
|
||||||
|
void compose(PageContext pageContext);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,366 +1,362 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64InputStream;
|
import org.apache.commons.codec.binary.Base64InputStream;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.rap.rwt.client.service.UrlLauncher;
|
import org.eclipse.rap.rwt.client.service.UrlLauncher;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.graphics.Image;
|
import org.eclipse.swt.graphics.Image;
|
||||||
import org.eclipse.swt.graphics.ImageData;
|
import org.eclipse.swt.graphics.ImageData;
|
||||||
import org.eclipse.swt.graphics.Rectangle;
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.layout.RowLayout;
|
import org.eclipse.swt.layout.RowLayout;
|
||||||
import org.eclipse.swt.widgets.Button;
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Display;
|
import org.eclipse.swt.widgets.Display;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.MessageBox;
|
import org.eclipse.swt.widgets.MessageBox;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
public class DefaultPageLayout implements TemplateComposer {
|
public class DefaultPageLayout implements TemplateComposer {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DefaultPageLayout.class);
|
private static final Logger log = LoggerFactory.getLogger(DefaultPageLayout.class);
|
||||||
|
|
||||||
private static final LocTextKey ABOUT_TEXT_KEY = new LocTextKey("sebserver.overall.about");
|
private static final LocTextKey ABOUT_TEXT_KEY = new LocTextKey("sebserver.overall.about");
|
||||||
private static final LocTextKey IMPRINT_TEXT_KEY = new LocTextKey("sebserver.overall.imprint");
|
private static final LocTextKey IMPRINT_TEXT_KEY = new LocTextKey("sebserver.overall.imprint");
|
||||||
private static final LocTextKey HELP_TEXT_KEY = new LocTextKey("sebserver.overall.help");
|
private static final LocTextKey HELP_TEXT_KEY = new LocTextKey("sebserver.overall.help");
|
||||||
|
|
||||||
private static final LocTextKey ABOUT_MARKUP_TEXT_KEY = new LocTextKey("sebserver.overall.about.markup");
|
private static final LocTextKey ABOUT_MARKUP_TEXT_KEY = new LocTextKey("sebserver.overall.about.markup");
|
||||||
private static final LocTextKey IMPRINT_MARKUP_TEXT_KEY = new LocTextKey("sebserver.overall.imprint.markup");
|
private static final LocTextKey IMPRINT_MARKUP_TEXT_KEY = new LocTextKey("sebserver.overall.imprint.markup");
|
||||||
private static final LocTextKey HELP_LINK_TEXT_KEY = new LocTextKey("sebserver.overall.help.link");
|
private static final LocTextKey HELP_LINK_TEXT_KEY = new LocTextKey("sebserver.overall.help.link");
|
||||||
|
|
||||||
public static final int LOGO_IMAGE_MAX_WIDTH = 400;
|
public static final int LOGO_IMAGE_MAX_WIDTH = 400;
|
||||||
public static final int LOGO_IMAGE_MAX_HEIGHT = 80;
|
public static final int LOGO_IMAGE_MAX_HEIGHT = 80;
|
||||||
|
|
||||||
private final WidgetFactory widgetFactory;
|
private final WidgetFactory widgetFactory;
|
||||||
private final PolyglotPageService polyglotPageService;
|
private final PolyglotPageService polyglotPageService;
|
||||||
private final AuthorizationContextHolder authorizationContextHolder;
|
private final AuthorizationContextHolder authorizationContextHolder;
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
private final String sebServerVersion;
|
private final String sebServerVersion;
|
||||||
private final boolean multilingual;
|
private final boolean multilingual;
|
||||||
|
|
||||||
public DefaultPageLayout(
|
public DefaultPageLayout(
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final Environment environment) {
|
final Environment environment) {
|
||||||
|
|
||||||
this.widgetFactory = pageService.getWidgetFactory();
|
this.widgetFactory = pageService.getWidgetFactory();
|
||||||
this.polyglotPageService = pageService.getPolyglotPageService();
|
this.polyglotPageService = pageService.getPolyglotPageService();
|
||||||
this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
|
this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
|
||||||
this.pageService = pageService;
|
this.pageService = pageService;
|
||||||
this.sebServerVersion = environment.getProperty("sebserver.version", Constants.EMPTY_NOTE);
|
this.sebServerVersion = environment.getProperty("sebserver.version", Constants.EMPTY_NOTE);
|
||||||
this.multilingual = BooleanUtils.toBoolean(environment.getProperty("sebserver.gui.multilingual", "false"));
|
this.multilingual = BooleanUtils.toBoolean(environment.getProperty("sebserver.gui.multilingual", "false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validate(final PageContext pageContext) {
|
public boolean validate(final PageContext pageContext) {
|
||||||
return pageContext.hasAttribute(AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME);
|
return pageContext.hasAttribute(AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compose(final PageContext pageContext) {
|
public void compose(final PageContext pageContext) {
|
||||||
|
|
||||||
final GridLayout skeletonLayout = new GridLayout();
|
final GridLayout skeletonLayout = new GridLayout();
|
||||||
skeletonLayout.marginBottom = 0;
|
skeletonLayout.marginBottom = 0;
|
||||||
skeletonLayout.marginLeft = 0;
|
skeletonLayout.marginLeft = 0;
|
||||||
skeletonLayout.marginRight = 0;
|
skeletonLayout.marginRight = 0;
|
||||||
skeletonLayout.marginTop = 0;
|
skeletonLayout.marginTop = 0;
|
||||||
skeletonLayout.marginHeight = 0;
|
skeletonLayout.marginHeight = 0;
|
||||||
skeletonLayout.marginWidth = 0;
|
skeletonLayout.marginWidth = 0;
|
||||||
skeletonLayout.verticalSpacing = 0;
|
skeletonLayout.verticalSpacing = 0;
|
||||||
skeletonLayout.horizontalSpacing = 0;
|
skeletonLayout.horizontalSpacing = 0;
|
||||||
pageContext.getParent().setLayout(skeletonLayout);
|
pageContext.getParent().setLayout(skeletonLayout);
|
||||||
|
|
||||||
composeHeader(pageContext);
|
composeHeader(pageContext);
|
||||||
composeLogoBar(pageContext);
|
composeLogoBar(pageContext);
|
||||||
composeContent(pageContext);
|
composeContent(pageContext);
|
||||||
composeFooter(pageContext);
|
composeFooter(pageContext);
|
||||||
|
|
||||||
this.polyglotPageService.setDefaultPageLocale(pageContext.getRoot());
|
this.polyglotPageService.setDefaultPageLocale(pageContext.getRoot());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void composeHeader(final PageContext pageContext) {
|
private void composeHeader(final PageContext pageContext) {
|
||||||
final Composite header = new Composite(pageContext.getParent(), SWT.NONE);
|
final Composite header = new Composite(pageContext.getParent(), SWT.NONE);
|
||||||
final GridLayout gridLayout = new GridLayout();
|
final GridLayout gridLayout = new GridLayout();
|
||||||
gridLayout.marginRight = 50;
|
gridLayout.marginRight = 50;
|
||||||
gridLayout.marginLeft = 50;
|
gridLayout.marginLeft = 50;
|
||||||
header.setLayout(gridLayout);
|
header.setLayout(gridLayout);
|
||||||
final GridData headerCell = new GridData(SWT.FILL, SWT.TOP, true, false);
|
final GridData headerCell = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||||
headerCell.minimumHeight = 40;
|
headerCell.minimumHeight = 40;
|
||||||
headerCell.heightHint = 40;
|
headerCell.heightHint = 40;
|
||||||
header.setLayoutData(headerCell);
|
header.setLayoutData(headerCell);
|
||||||
header.setData(RWT.CUSTOM_VARIANT, "header");
|
header.setData(RWT.CUSTOM_VARIANT, "header");
|
||||||
|
|
||||||
final Composite headerRight = new Composite(header, SWT.NONE);
|
final Composite headerRight = new Composite(header, SWT.NONE);
|
||||||
headerRight.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true));
|
headerRight.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true));
|
||||||
final GridLayout headerRightGrid = new GridLayout(2, false);
|
final GridLayout headerRightGrid = new GridLayout(2, false);
|
||||||
headerRightGrid.marginHeight = 0;
|
headerRightGrid.marginHeight = 0;
|
||||||
headerRightGrid.marginWidth = 0;
|
headerRightGrid.marginWidth = 0;
|
||||||
headerRightGrid.horizontalSpacing = 20;
|
headerRightGrid.horizontalSpacing = 20;
|
||||||
headerRight.setLayout(headerRightGrid);
|
headerRight.setLayout(headerRightGrid);
|
||||||
headerRight.setData(RWT.CUSTOM_VARIANT, "header");
|
headerRight.setData(RWT.CUSTOM_VARIANT, "header");
|
||||||
|
|
||||||
if (this.authorizationContextHolder.getAuthorizationContext().isLoggedIn()) {
|
if (this.authorizationContextHolder.getAuthorizationContext().isLoggedIn()) {
|
||||||
final Label username = new Label(headerRight, SWT.NONE);
|
final Label username = new Label(headerRight, SWT.NONE);
|
||||||
username.setData(RWT.CUSTOM_VARIANT, "header");
|
username.setData(RWT.CUSTOM_VARIANT, "header");
|
||||||
username.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true));
|
username.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true));
|
||||||
username.setText(this.authorizationContextHolder
|
username.setText(this.authorizationContextHolder
|
||||||
.getAuthorizationContext()
|
.getAuthorizationContext()
|
||||||
.getLoggedInUser()
|
.getLoggedInUser()
|
||||||
.get(t -> this.pageService.logoutOnError(t, pageContext)).username);
|
.get(t -> this.pageService.logoutOnError(t, pageContext)).username);
|
||||||
|
|
||||||
final Button logout = this.widgetFactory.buttonLocalized(headerRight, "sebserver.logout");
|
final Button logout = this.widgetFactory.buttonLocalized(headerRight, "sebserver.logout");
|
||||||
logout.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
|
logout.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true));
|
||||||
logout.setData(RWT.CUSTOM_VARIANT, "header");
|
logout.setData(RWT.CUSTOM_VARIANT, "header");
|
||||||
logout.addListener(SWT.Selection, event -> {
|
logout.addListener(SWT.Selection, event -> {
|
||||||
this.pageService.logout(pageContext);
|
this.pageService.logout(pageContext);
|
||||||
// show successful logout message
|
// show successful logout message
|
||||||
final MessageBox logoutSuccess = new Message(
|
final MessageBox logoutSuccess = new Message(
|
||||||
pageContext.getShell(),
|
pageContext.getShell(),
|
||||||
this.polyglotPageService.getI18nSupport().getText("sebserver.logout"),
|
this.polyglotPageService.getI18nSupport().getText("sebserver.logout"),
|
||||||
this.polyglotPageService.getI18nSupport().getText("sebserver.logout.success.message"),
|
this.polyglotPageService.getI18nSupport().getText("sebserver.logout.success.message"),
|
||||||
SWT.ICON_INFORMATION,
|
SWT.ICON_INFORMATION,
|
||||||
pageContext.getI18nSupport());
|
pageContext.getI18nSupport());
|
||||||
logoutSuccess.open(null);
|
logoutSuccess.open(null);
|
||||||
|
|
||||||
// TODO Try to invalidate RWT's user session.
|
// TODO Try to invalidate RWT's user session.
|
||||||
// This seems to be more difficult then expected and just invalidate the HttpSession dosn't work
|
// This seems to be more difficult then expected and just invalidate the HttpSession doesn't work
|
||||||
// Try to send a redirect JSON to the client: https://bugs.eclipse.org/bugs/show_bug.cgi?id=388249
|
// Try to send a redirect JSON to the client: https://bugs.eclipse.org/bugs/show_bug.cgi?id=388249
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void composeLogoBar(final PageContext pageContext) {
|
private void composeLogoBar(final PageContext pageContext) {
|
||||||
final Composite logoBar = new Composite(pageContext.getParent(), SWT.NONE);
|
final Composite logoBar = new Composite(pageContext.getParent(), SWT.NONE);
|
||||||
final GridData logoBarCell = new GridData(SWT.FILL, SWT.TOP, false, false);
|
final GridData logoBarCell = new GridData(SWT.FILL, SWT.TOP, false, false);
|
||||||
logoBarCell.minimumHeight = 80;
|
logoBarCell.minimumHeight = 80;
|
||||||
logoBarCell.heightHint = 80;
|
logoBarCell.heightHint = 80;
|
||||||
logoBar.setLayoutData(logoBarCell);
|
logoBar.setLayoutData(logoBarCell);
|
||||||
logoBar.setData(RWT.CUSTOM_VARIANT, "logo");
|
logoBar.setData(RWT.CUSTOM_VARIANT, "logo");
|
||||||
final GridLayout logoBarLayout = new GridLayout(2, false);
|
final GridLayout logoBarLayout = new GridLayout(2, false);
|
||||||
logoBarLayout.horizontalSpacing = 0;
|
logoBarLayout.horizontalSpacing = 0;
|
||||||
logoBarLayout.marginHeight = 0;
|
logoBarLayout.marginHeight = 0;
|
||||||
logoBar.setLayout(logoBarLayout);
|
logoBar.setLayout(logoBarLayout);
|
||||||
|
|
||||||
final Composite logo = new Composite(logoBar, SWT.NONE);
|
final Composite logo = new Composite(logoBar, SWT.NONE);
|
||||||
final GridData logoCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
final GridData logoCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
||||||
logoCell.minimumHeight = LOGO_IMAGE_MAX_HEIGHT;
|
logoCell.minimumHeight = LOGO_IMAGE_MAX_HEIGHT;
|
||||||
logoCell.heightHint = LOGO_IMAGE_MAX_HEIGHT;
|
logoCell.heightHint = LOGO_IMAGE_MAX_HEIGHT;
|
||||||
logoCell.minimumWidth = LOGO_IMAGE_MAX_WIDTH;
|
logoCell.minimumWidth = LOGO_IMAGE_MAX_WIDTH;
|
||||||
logoCell.horizontalIndent = 50;
|
logoCell.horizontalIndent = 50;
|
||||||
logo.setLayoutData(logoCell);
|
logo.setLayoutData(logoCell);
|
||||||
|
|
||||||
// try to get institutional logo first. If no success, use default logo
|
// try to get institutional logo first. If no success, use default logo
|
||||||
loadInstitutionalLogo(pageContext, logo);
|
loadInstitutionalLogo(pageContext, logo);
|
||||||
|
|
||||||
final Composite langSupport = new Composite(logoBar, SWT.NONE);
|
final Composite langSupport = new Composite(logoBar, SWT.NONE);
|
||||||
final GridData langSupportCell = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
|
final GridData langSupportCell = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
|
||||||
langSupportCell.heightHint = 20;
|
langSupportCell.heightHint = 20;
|
||||||
logoCell.horizontalIndent = 50;
|
logoCell.horizontalIndent = 50;
|
||||||
langSupport.setLayoutData(langSupportCell);
|
langSupport.setLayoutData(langSupportCell);
|
||||||
langSupport.setData(RWT.CUSTOM_VARIANT, "logo");
|
langSupport.setData(RWT.CUSTOM_VARIANT, "logo");
|
||||||
final RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL);
|
final RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL);
|
||||||
rowLayout.spacing = 7;
|
rowLayout.spacing = 7;
|
||||||
rowLayout.marginRight = 70;
|
rowLayout.marginRight = 70;
|
||||||
langSupport.setLayout(rowLayout);
|
langSupport.setLayout(rowLayout);
|
||||||
|
|
||||||
if (this.multilingual) {
|
if (this.multilingual) {
|
||||||
this.polyglotPageService.createLanguageSelector(pageContext.copyOf(langSupport));
|
this.polyglotPageService.createLanguageSelector(pageContext.copyOf(langSupport));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void composeContent(final PageContext pageContext) {
|
private void composeContent(final PageContext pageContext) {
|
||||||
final Composite contentBackground = new Composite(pageContext.getParent(), SWT.NONE);
|
final Composite contentBackground = new Composite(pageContext.getParent(), SWT.NONE);
|
||||||
contentBackground.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
contentBackground.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||||
contentBackground.setData(RWT.CUSTOM_VARIANT, "bgContent");
|
contentBackground.setData(RWT.CUSTOM_VARIANT, "bgContent");
|
||||||
final GridLayout innerGrid = new GridLayout();
|
final GridLayout innerGrid = new GridLayout();
|
||||||
innerGrid.marginLeft = 50;
|
innerGrid.marginLeft = 50;
|
||||||
innerGrid.marginRight = 50;
|
innerGrid.marginRight = 50;
|
||||||
innerGrid.marginHeight = 0;
|
innerGrid.marginHeight = 0;
|
||||||
innerGrid.marginWidth = 0;
|
innerGrid.marginWidth = 0;
|
||||||
|
|
||||||
contentBackground.setLayout(innerGrid);
|
contentBackground.setLayout(innerGrid);
|
||||||
|
|
||||||
final Composite content = new Composite(contentBackground, SWT.NONE);
|
final Composite content = new Composite(contentBackground, SWT.NONE);
|
||||||
content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||||
content.setData(RWT.CUSTOM_VARIANT, "content");
|
content.setData(RWT.CUSTOM_VARIANT, "content");
|
||||||
final GridLayout contentGrid = new GridLayout();
|
final GridLayout contentGrid = new GridLayout();
|
||||||
contentGrid.marginHeight = 0;
|
contentGrid.marginHeight = 0;
|
||||||
contentGrid.marginWidth = 0;
|
contentGrid.marginWidth = 0;
|
||||||
content.setLayout(contentGrid);
|
content.setLayout(contentGrid);
|
||||||
|
|
||||||
final Composite contentInner = new Composite(content, SWT.NONE);
|
final Composite contentInner = new Composite(content, SWT.NONE);
|
||||||
contentInner.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
|
contentInner.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
|
||||||
final GridLayout gridLayout = new GridLayout();
|
final GridLayout gridLayout = new GridLayout();
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.marginHeight = 0;
|
||||||
gridLayout.marginWidth = 0;
|
gridLayout.marginWidth = 0;
|
||||||
contentInner.setLayout(gridLayout);
|
contentInner.setLayout(gridLayout);
|
||||||
|
|
||||||
final String contentComposerName = pageContext.getAttribute(
|
final String contentComposerName = pageContext.getAttribute(
|
||||||
AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME);
|
AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME);
|
||||||
pageContext.composerService().compose(
|
pageContext.composerService().compose(
|
||||||
contentComposerName,
|
contentComposerName,
|
||||||
pageContext.copyOf(contentInner));
|
pageContext.copyOf(contentInner));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void composeFooter(final PageContext pageContext) {
|
private void composeFooter(final PageContext pageContext) {
|
||||||
final Composite footerBar = new Composite(pageContext.getParent(), SWT.NONE);
|
final Composite footerBar = new Composite(pageContext.getParent(), SWT.NONE);
|
||||||
final GridData footerCell = new GridData(SWT.FILL, SWT.BOTTOM, false, false);
|
final GridData footerCell = new GridData(SWT.FILL, SWT.BOTTOM, false, false);
|
||||||
footerCell.minimumHeight = 30;
|
footerCell.minimumHeight = 30;
|
||||||
footerCell.heightHint = 30;
|
footerCell.heightHint = 30;
|
||||||
footerBar.setLayoutData(footerCell);
|
footerBar.setLayoutData(footerCell);
|
||||||
footerBar.setData(RWT.CUSTOM_VARIANT, "bgFooter");
|
footerBar.setData(RWT.CUSTOM_VARIANT, "bgFooter");
|
||||||
final GridLayout innerBarGrid = new GridLayout();
|
final GridLayout innerBarGrid = new GridLayout();
|
||||||
innerBarGrid.marginHeight = 0;
|
innerBarGrid.marginHeight = 0;
|
||||||
innerBarGrid.marginWidth = 0;
|
innerBarGrid.marginWidth = 0;
|
||||||
innerBarGrid.marginLeft = 50;
|
innerBarGrid.marginLeft = 50;
|
||||||
innerBarGrid.marginRight = 50;
|
innerBarGrid.marginRight = 50;
|
||||||
footerBar.setLayout(innerBarGrid);
|
footerBar.setLayout(innerBarGrid);
|
||||||
|
|
||||||
final Composite footer = new Composite(footerBar, SWT.NONE);
|
final Composite footer = new Composite(footerBar, SWT.NONE);
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
footer.setLayoutData(gridData);
|
footer.setLayoutData(gridData);
|
||||||
final GridLayout footerGrid = new GridLayout(2, false);
|
final GridLayout footerGrid = new GridLayout(2, false);
|
||||||
footerGrid.marginHeight = 0;
|
footerGrid.marginHeight = 0;
|
||||||
footerGrid.marginWidth = 0;
|
footerGrid.marginWidth = 0;
|
||||||
footerGrid.horizontalSpacing = 0;
|
footerGrid.horizontalSpacing = 0;
|
||||||
footer.setLayout(footerGrid);
|
footer.setLayout(footerGrid);
|
||||||
footer.setData(RWT.CUSTOM_VARIANT, "footer");
|
footer.setData(RWT.CUSTOM_VARIANT, "footer");
|
||||||
|
|
||||||
final Composite footerLeft = new Composite(footer, SWT.NONE);
|
final Composite footerLeft = new Composite(footer, SWT.NONE);
|
||||||
footerLeft.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true));
|
footerLeft.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true));
|
||||||
footerLeft.setData(RWT.CUSTOM_VARIANT, "footer");
|
footerLeft.setData(RWT.CUSTOM_VARIANT, "footer");
|
||||||
RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL);
|
RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL);
|
||||||
rowLayout.marginLeft = 20;
|
rowLayout.marginLeft = 20;
|
||||||
rowLayout.spacing = 20;
|
rowLayout.spacing = 20;
|
||||||
footerLeft.setLayout(rowLayout);
|
footerLeft.setLayout(rowLayout);
|
||||||
|
|
||||||
final Composite footerRight = new Composite(footer, SWT.NONE);
|
final Composite footerRight = new Composite(footer, SWT.NONE);
|
||||||
footerRight.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true));
|
footerRight.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true));
|
||||||
footerRight.setData(RWT.CUSTOM_VARIANT, "footer");
|
footerRight.setData(RWT.CUSTOM_VARIANT, "footer");
|
||||||
rowLayout = new RowLayout(SWT.HORIZONTAL);
|
rowLayout = new RowLayout(SWT.HORIZONTAL);
|
||||||
rowLayout.marginRight = 20;
|
rowLayout.marginRight = 20;
|
||||||
footerRight.setLayout(rowLayout);
|
footerRight.setLayout(rowLayout);
|
||||||
|
|
||||||
final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport();
|
final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport();
|
||||||
if (StringUtils.isNoneBlank(i18nSupport.getText(IMPRINT_TEXT_KEY, ""))) {
|
if (StringUtils.isNoneBlank(i18nSupport.getText(IMPRINT_TEXT_KEY, ""))) {
|
||||||
final Label imprint = this.widgetFactory.labelLocalized(
|
final Label imprint = this.widgetFactory.labelLocalized(
|
||||||
footerLeft,
|
footerLeft,
|
||||||
CustomVariant.FOOTER,
|
CustomVariant.FOOTER,
|
||||||
IMPRINT_TEXT_KEY);
|
IMPRINT_TEXT_KEY);
|
||||||
|
|
||||||
imprint.addListener(SWT.MouseUp, event -> {
|
imprint.addListener(SWT.MouseUp, event -> {
|
||||||
try {
|
try {
|
||||||
pageContext.publishPageMessage(IMPRINT_TEXT_KEY, IMPRINT_MARKUP_TEXT_KEY);
|
pageContext.publishPageMessage(IMPRINT_TEXT_KEY, IMPRINT_MARKUP_TEXT_KEY);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Invalid markup for 'Imprint'", e);
|
log.error("Invalid markup for 'Imprint'", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (StringUtils.isNoneBlank(i18nSupport.getText(ABOUT_TEXT_KEY, ""))) {
|
if (StringUtils.isNoneBlank(i18nSupport.getText(ABOUT_TEXT_KEY, ""))) {
|
||||||
final Label about = this.widgetFactory.labelLocalized(
|
final Label about = this.widgetFactory.labelLocalized(
|
||||||
footerLeft,
|
footerLeft,
|
||||||
CustomVariant.FOOTER,
|
CustomVariant.FOOTER,
|
||||||
ABOUT_TEXT_KEY);
|
ABOUT_TEXT_KEY);
|
||||||
|
|
||||||
about.addListener(SWT.MouseUp, event -> {
|
about.addListener(SWT.MouseUp, event -> {
|
||||||
try {
|
try {
|
||||||
pageContext.publishPageMessage(ABOUT_TEXT_KEY, ABOUT_MARKUP_TEXT_KEY);
|
pageContext.publishPageMessage(ABOUT_TEXT_KEY, ABOUT_MARKUP_TEXT_KEY);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Invalid markup for 'About'", e);
|
log.error("Invalid markup for 'About'", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (StringUtils.isNoneBlank(i18nSupport.getText(HELP_TEXT_KEY, ""))) {
|
if (StringUtils.isNoneBlank(i18nSupport.getText(HELP_TEXT_KEY, ""))) {
|
||||||
final Label help = this.widgetFactory.labelLocalized(
|
final Label help = this.widgetFactory.labelLocalized(
|
||||||
footerLeft,
|
footerLeft,
|
||||||
CustomVariant.FOOTER,
|
CustomVariant.FOOTER,
|
||||||
HELP_TEXT_KEY);
|
HELP_TEXT_KEY);
|
||||||
|
|
||||||
help.addListener(SWT.MouseUp, event -> {
|
help.addListener(SWT.MouseUp, event -> {
|
||||||
try {
|
try {
|
||||||
final String link = i18nSupport.getText(HELP_LINK_TEXT_KEY, "");
|
final String link = i18nSupport.getText(HELP_LINK_TEXT_KEY, "");
|
||||||
if (StringUtils.isNoneBlank(link)) {
|
if (StringUtils.isNoneBlank(link)) {
|
||||||
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
||||||
urlLauncher.openURL(link);
|
urlLauncher.openURL(link);
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Invalid Help link", e);
|
log.error("Invalid Help link", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
this.widgetFactory.labelLocalized(
|
this.widgetFactory.labelLocalized(
|
||||||
footerRight,
|
footerRight,
|
||||||
CustomVariant.FOOTER,
|
CustomVariant.FOOTER,
|
||||||
new LocTextKey("sebserver.overall.version", this.sebServerVersion));
|
new LocTextKey("sebserver.overall.version", this.sebServerVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadInstitutionalLogo(final PageContext pageContext, final Composite logo) {
|
private void loadInstitutionalLogo(final PageContext pageContext, final Composite logo) {
|
||||||
logo.setData(RWT.CUSTOM_VARIANT, "bgLogo");
|
logo.setData(RWT.CUSTOM_VARIANT, "bgLogo");
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final String imageBase64 = (String) RWT.getUISession()
|
final String imageBase64 = (String) RWT.getUISession()
|
||||||
.getHttpSession()
|
.getHttpSession()
|
||||||
.getAttribute(API.PARAM_LOGO_IMAGE);
|
.getAttribute(API.PARAM_LOGO_IMAGE);
|
||||||
|
|
||||||
if (StringUtils.isBlank(imageBase64)) {
|
if (StringUtils.isBlank(imageBase64)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Base64InputStream input = new Base64InputStream(
|
final Base64InputStream input = new Base64InputStream(
|
||||||
new ByteArrayInputStream(imageBase64.getBytes(StandardCharsets.UTF_8)),
|
new ByteArrayInputStream(imageBase64.getBytes(StandardCharsets.UTF_8)),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
final Display display = pageContext.getShell().getDisplay();
|
final Display display = pageContext.getShell().getDisplay();
|
||||||
final Image image = new Image(display, input);
|
final Image image = new Image(display, input);
|
||||||
final Rectangle imageBounds = image.getBounds();
|
final Rectangle imageBounds = image.getBounds();
|
||||||
final int width = (imageBounds.width > LOGO_IMAGE_MAX_WIDTH)
|
final int width = Math.min(imageBounds.width, LOGO_IMAGE_MAX_WIDTH);
|
||||||
? LOGO_IMAGE_MAX_WIDTH
|
final int height = Math.min(imageBounds.height, LOGO_IMAGE_MAX_HEIGHT);
|
||||||
: imageBounds.width;
|
final ImageData imageData = image.getImageData().scaledTo(width, height);
|
||||||
final int height = (imageBounds.height > LOGO_IMAGE_MAX_HEIGHT)
|
|
||||||
? LOGO_IMAGE_MAX_HEIGHT
|
logo.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");
|
||||||
: imageBounds.height;
|
logo.setBackgroundImage(new Image(display, imageData));
|
||||||
final ImageData imageData = image.getImageData().scaledTo(width, height);
|
|
||||||
|
} catch (final Exception e) {
|
||||||
logo.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");
|
log.warn("Get institutional logo failed: {}", e.getMessage());
|
||||||
logo.setBackgroundImage(new Image(display, imageData));
|
}
|
||||||
|
}
|
||||||
} catch (final Exception e) {
|
|
||||||
log.warn("Get institutional logo failed: {}", e.getMessage());
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,225 +1,220 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.graphics.Rectangle;
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Button;
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Dialog;
|
import org.eclipse.swt.widgets.Dialog;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||||
|
|
||||||
public class ModalInputDialog<T> extends Dialog {
|
public class ModalInputDialog<T> extends Dialog {
|
||||||
|
|
||||||
private static final long serialVersionUID = -3448614119078234374L;
|
private static final long serialVersionUID = -3448614119078234374L;
|
||||||
|
|
||||||
public static final int DEFAULT_DIALOG_WIDTH = 400;
|
public static final int DEFAULT_DIALOG_WIDTH = 400;
|
||||||
public static final int DEFAULT_DIALOG_HEIGHT = 600;
|
public static final int DEFAULT_DIALOG_HEIGHT = 600;
|
||||||
public static final int DEFAULT_DIALOG_BUTTON_WIDTH = 100;
|
public static final int DEFAULT_DIALOG_BUTTON_WIDTH = 100;
|
||||||
public static final int LARGE_DIALOG_WIDTH = 600;
|
public static final int LARGE_DIALOG_WIDTH = 600;
|
||||||
public static final int VERY_LARGE_DIALOG_WIDTH = 800;
|
public static final int VERY_LARGE_DIALOG_WIDTH = 800;
|
||||||
|
|
||||||
private static final LocTextKey CANCEL_TEXT_KEY =
|
private static final LocTextKey CANCEL_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.overall.action.cancel");
|
new LocTextKey("sebserver.overall.action.cancel");
|
||||||
private static final LocTextKey OK_TEXT_KEY =
|
private static final LocTextKey OK_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.overall.action.ok");
|
new LocTextKey("sebserver.overall.action.ok");
|
||||||
private static final LocTextKey CLOSE_TEXT_KEY =
|
private static final LocTextKey CLOSE_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.overall.action.close");
|
new LocTextKey("sebserver.overall.action.close");
|
||||||
|
|
||||||
private final WidgetFactory widgetFactory;
|
private final WidgetFactory widgetFactory;
|
||||||
private int dialogWidth = DEFAULT_DIALOG_WIDTH;
|
private int dialogWidth = DEFAULT_DIALOG_WIDTH;
|
||||||
private int dialogHeight = DEFAULT_DIALOG_HEIGHT;
|
private int dialogHeight = DEFAULT_DIALOG_HEIGHT;
|
||||||
private int buttonWidth = DEFAULT_DIALOG_BUTTON_WIDTH;
|
private int buttonWidth = DEFAULT_DIALOG_BUTTON_WIDTH;
|
||||||
|
|
||||||
public ModalInputDialog(
|
public ModalInputDialog(
|
||||||
final Shell parent,
|
final Shell parent,
|
||||||
final WidgetFactory widgetFactory) {
|
final WidgetFactory widgetFactory) {
|
||||||
|
|
||||||
super(parent, SWT.BORDER | SWT.TITLE | SWT.APPLICATION_MODAL | SWT.CLOSE);
|
super(parent, SWT.BORDER | SWT.TITLE | SWT.APPLICATION_MODAL | SWT.CLOSE);
|
||||||
this.widgetFactory = widgetFactory;
|
this.widgetFactory = widgetFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModalInputDialog<T> setDialogWidth(final int dialogWidth) {
|
public ModalInputDialog<T> setDialogWidth(final int dialogWidth) {
|
||||||
this.dialogWidth = dialogWidth;
|
this.dialogWidth = dialogWidth;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModalInputDialog<T> setLargeDialogWidth() {
|
public ModalInputDialog<T> setLargeDialogWidth() {
|
||||||
this.dialogWidth = LARGE_DIALOG_WIDTH;
|
this.dialogWidth = LARGE_DIALOG_WIDTH;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModalInputDialog<T> setVeryLargeDialogWidth() {
|
public ModalInputDialog<T> setVeryLargeDialogWidth() {
|
||||||
this.dialogWidth = VERY_LARGE_DIALOG_WIDTH;
|
this.dialogWidth = VERY_LARGE_DIALOG_WIDTH;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModalInputDialog<T> setDialogHeight(final int dialogHeight) {
|
public ModalInputDialog<T> setDialogHeight(final int dialogHeight) {
|
||||||
this.dialogHeight = dialogHeight;
|
this.dialogHeight = dialogHeight;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModalInputDialog<T> setButtonWidth(final int buttonWidth) {
|
public ModalInputDialog<T> setButtonWidth(final int buttonWidth) {
|
||||||
this.buttonWidth = buttonWidth;
|
this.buttonWidth = buttonWidth;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(
|
public void open(
|
||||||
final LocTextKey title,
|
final LocTextKey title,
|
||||||
final ModalInputDialogComposer<T> contentComposer) {
|
final ModalInputDialogComposer<T> contentComposer) {
|
||||||
|
|
||||||
open(
|
open(
|
||||||
title,
|
title,
|
||||||
(Predicate<T>) t -> true,
|
t -> true,
|
||||||
() -> {
|
() -> {
|
||||||
}, contentComposer);
|
}, contentComposer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(
|
public void open(
|
||||||
final LocTextKey title,
|
final LocTextKey title,
|
||||||
final Consumer<T> callback,
|
final Consumer<T> callback,
|
||||||
final Runnable cancelCallback,
|
final Runnable cancelCallback,
|
||||||
final ModalInputDialogComposer<T> contentComposer) {
|
final ModalInputDialogComposer<T> contentComposer) {
|
||||||
|
|
||||||
final Predicate<T> predicate = result -> {
|
final Predicate<T> predicate = result -> {
|
||||||
callback.accept(result);
|
callback.accept(result);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
open(title, predicate, cancelCallback, contentComposer);
|
open(title, predicate, cancelCallback, contentComposer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(
|
public void open(
|
||||||
final LocTextKey title,
|
final LocTextKey title,
|
||||||
final Predicate<T> callback,
|
final Predicate<T> callback,
|
||||||
final Runnable cancelCallback,
|
final Runnable cancelCallback,
|
||||||
final ModalInputDialogComposer<T> contentComposer) {
|
final ModalInputDialogComposer<T> contentComposer) {
|
||||||
|
|
||||||
// Create the selection dialog window
|
// Create the selection dialog window
|
||||||
final Shell shell = new Shell(getParent(), getStyle());
|
final Shell shell = new Shell(getParent(), getStyle());
|
||||||
shell.setText(getText());
|
shell.setText(getText());
|
||||||
shell.setData(RWT.CUSTOM_VARIANT, CustomVariant.MESSAGE.key);
|
shell.setData(RWT.CUSTOM_VARIANT, CustomVariant.MESSAGE.key);
|
||||||
shell.setText(this.widgetFactory.getI18nSupport().getText(title));
|
shell.setText(this.widgetFactory.getI18nSupport().getText(title));
|
||||||
shell.setLayout(new GridLayout(2, true));
|
shell.setLayout(new GridLayout(2, true));
|
||||||
final GridData gridData2 = new GridData(SWT.FILL, SWT.TOP, false, false);
|
final GridData gridData2 = new GridData(SWT.FILL, SWT.TOP, false, false);
|
||||||
shell.setLayoutData(gridData2);
|
shell.setLayoutData(gridData2);
|
||||||
|
|
||||||
final Composite main = new Composite(shell, SWT.NONE);
|
final Composite main = new Composite(shell, SWT.NONE);
|
||||||
main.setLayout(new GridLayout());
|
main.setLayout(new GridLayout());
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
gridData.horizontalSpan = 2;
|
gridData.horizontalSpan = 2;
|
||||||
gridData.widthHint = this.dialogWidth;
|
gridData.widthHint = this.dialogWidth;
|
||||||
main.setLayoutData(gridData);
|
main.setLayoutData(gridData);
|
||||||
|
|
||||||
final Supplier<T> valueSuppier = contentComposer.compose(main);
|
final Supplier<T> valueSupplier = contentComposer.compose(main);
|
||||||
gridData.heightHint = calcDialogHeight(main);
|
gridData.heightHint = calcDialogHeight(main);
|
||||||
|
|
||||||
final Button ok = this.widgetFactory.buttonLocalized(shell, OK_TEXT_KEY);
|
final Button ok = this.widgetFactory.buttonLocalized(shell, OK_TEXT_KEY);
|
||||||
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END);
|
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END);
|
||||||
data.widthHint = this.buttonWidth;
|
data.widthHint = this.buttonWidth;
|
||||||
ok.setLayoutData(data);
|
ok.setLayoutData(data);
|
||||||
ok.addListener(SWT.Selection, event -> {
|
ok.addListener(SWT.Selection, event -> {
|
||||||
if (valueSuppier != null) {
|
if (valueSupplier != null) {
|
||||||
final T result = valueSuppier.get();
|
final T result = valueSupplier.get();
|
||||||
if (callback.test(result)) {
|
if (callback.test(result)) {
|
||||||
shell.close();
|
shell.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shell.close();
|
shell.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
shell.setDefaultButton(ok);
|
shell.setDefaultButton(ok);
|
||||||
|
|
||||||
final Button cancel = this.widgetFactory.buttonLocalized(shell, CANCEL_TEXT_KEY);
|
final Button cancel = this.widgetFactory.buttonLocalized(shell, CANCEL_TEXT_KEY);
|
||||||
data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
|
data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
|
||||||
data.widthHint = this.buttonWidth;
|
data.widthHint = this.buttonWidth;
|
||||||
cancel.setLayoutData(data);
|
cancel.setLayoutData(data);
|
||||||
cancel.addListener(SWT.Selection, event -> {
|
cancel.addListener(SWT.Selection, event -> {
|
||||||
if (cancelCallback != null) {
|
if (cancelCallback != null) {
|
||||||
cancelCallback.run();
|
cancelCallback.run();
|
||||||
}
|
}
|
||||||
shell.close();
|
shell.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
finishUp(shell);
|
finishUp(shell);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(
|
public void open(
|
||||||
final LocTextKey title,
|
final LocTextKey title,
|
||||||
final PageContext pageContext,
|
final PageContext pageContext,
|
||||||
final Consumer<PageContext> contentComposer) {
|
final Consumer<PageContext> contentComposer) {
|
||||||
|
|
||||||
// Create the info dialog window
|
// Create the info dialog window
|
||||||
final Shell shell = new Shell(getParent(), getStyle());
|
final Shell shell = new Shell(getParent(), getStyle());
|
||||||
shell.setText(getText());
|
shell.setText(getText());
|
||||||
shell.setData(RWT.CUSTOM_VARIANT, CustomVariant.MESSAGE.key);
|
shell.setData(RWT.CUSTOM_VARIANT, CustomVariant.MESSAGE.key);
|
||||||
shell.setText(this.widgetFactory.getI18nSupport().getText(title));
|
shell.setText(this.widgetFactory.getI18nSupport().getText(title));
|
||||||
shell.setLayout(new GridLayout());
|
shell.setLayout(new GridLayout());
|
||||||
final GridData gridData2 = new GridData(SWT.FILL, SWT.TOP, true, true);
|
final GridData gridData2 = new GridData(SWT.FILL, SWT.TOP, true, true);
|
||||||
|
|
||||||
shell.setLayoutData(gridData2);
|
shell.setLayoutData(gridData2);
|
||||||
|
|
||||||
final Composite main = new Composite(shell, SWT.NONE);
|
final Composite main = new Composite(shell, SWT.NONE);
|
||||||
main.setLayout(new GridLayout());
|
main.setLayout(new GridLayout());
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
|
||||||
gridData.widthHint = this.dialogWidth;
|
gridData.widthHint = this.dialogWidth;
|
||||||
main.setLayoutData(gridData);
|
main.setLayoutData(gridData);
|
||||||
|
|
||||||
contentComposer.accept(pageContext.copyOf(main));
|
contentComposer.accept(pageContext.copyOf(main));
|
||||||
gridData.heightHint = calcDialogHeight(main);
|
gridData.heightHint = calcDialogHeight(main);
|
||||||
|
|
||||||
final Button close = this.widgetFactory.buttonLocalized(shell, CLOSE_TEXT_KEY);
|
final Button close = this.widgetFactory.buttonLocalized(shell, CLOSE_TEXT_KEY);
|
||||||
final GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
|
final GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
|
||||||
data.widthHint = this.buttonWidth;
|
data.widthHint = this.buttonWidth;
|
||||||
close.setLayoutData(data);
|
close.setLayoutData(data);
|
||||||
close.addListener(SWT.Selection, event -> {
|
close.addListener(SWT.Selection, event -> shell.close());
|
||||||
shell.close();
|
|
||||||
});
|
finishUp(shell);
|
||||||
|
}
|
||||||
finishUp(shell);
|
|
||||||
}
|
private void finishUp(final Shell shell) {
|
||||||
|
shell.pack();
|
||||||
private void finishUp(final Shell shell) {
|
final Rectangle bounds = shell.getBounds();
|
||||||
shell.pack();
|
final Rectangle bounds2 = super.getParent().getDisplay().getBounds();
|
||||||
final Rectangle bounds = shell.getBounds();
|
bounds.x = (bounds2.width - bounds.width) / 2;
|
||||||
final Rectangle bounds2 = super.getParent().getDisplay().getBounds();
|
bounds.y = (bounds2.height - bounds.height) / 2;
|
||||||
bounds.x = (bounds2.width - bounds.width) / 2;
|
shell.setBounds(bounds);
|
||||||
bounds.y = (bounds2.height - bounds.height) / 2;
|
|
||||||
shell.setBounds(bounds);
|
shell.open();
|
||||||
|
}
|
||||||
shell.open();
|
|
||||||
}
|
private int calcDialogHeight(final Composite main) {
|
||||||
|
final int actualHeight = main.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
|
||||||
private int calcDialogHeight(final Composite main) {
|
final int displayHeight = main.getDisplay().getClientArea().height;
|
||||||
final int actualHeight = main.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
|
final int availableHeight = (displayHeight < actualHeight + 100)
|
||||||
final int displayHeight = main.getDisplay().getClientArea().height;
|
? displayHeight - 100
|
||||||
final int availableHeight = (displayHeight < actualHeight + 100)
|
: actualHeight;
|
||||||
? displayHeight - 100
|
return Math.min(availableHeight, this.dialogHeight);
|
||||||
: actualHeight;
|
}
|
||||||
final int height = (availableHeight > this.dialogHeight)
|
|
||||||
? this.dialogHeight
|
}
|
||||||
: availableHeight;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,346 +1,340 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.eclipse.rap.rwt.widgets.DialogCallback;
|
import org.eclipse.rap.rwt.widgets.DialogCallback;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.MessageBox;
|
import org.eclipse.swt.widgets.MessageBox;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||||
|
|
||||||
public class PageContextImpl implements PageContext {
|
public class PageContextImpl implements PageContext {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PageContextImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(PageContextImpl.class);
|
||||||
|
|
||||||
private final I18nSupport i18nSupport;
|
private final I18nSupport i18nSupport;
|
||||||
private final ComposerService composerService;
|
private final ComposerService composerService;
|
||||||
private final Composite root;
|
private final Composite root;
|
||||||
private final Composite parent;
|
private final Composite parent;
|
||||||
private final Map<String, String> attributes;
|
private final Map<String, String> attributes;
|
||||||
|
|
||||||
PageContextImpl(
|
PageContextImpl(
|
||||||
final I18nSupport i18nSupport,
|
final I18nSupport i18nSupport,
|
||||||
final ComposerService composerService,
|
final ComposerService composerService,
|
||||||
final Composite root,
|
final Composite root,
|
||||||
final Composite parent,
|
final Composite parent,
|
||||||
final Map<String, String> attributes) {
|
final Map<String, String> attributes) {
|
||||||
|
|
||||||
this.i18nSupport = i18nSupport;
|
this.i18nSupport = i18nSupport;
|
||||||
this.composerService = composerService;
|
this.composerService = composerService;
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.attributes = Utils.immutableMapOf(attributes);
|
this.attributes = Utils.immutableMapOf(attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public I18nSupport getI18nSupport() {
|
public I18nSupport getI18nSupport() {
|
||||||
return this.i18nSupport;
|
return this.i18nSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Shell getShell() {
|
public Shell getShell() {
|
||||||
if (this.root == null) {
|
if (this.root == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.root.getShell();
|
return this.root.getShell();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ComposerService composerService() {
|
public ComposerService composerService() {
|
||||||
return this.composerService;
|
return this.composerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Composite getRoot() {
|
public Composite getRoot() {
|
||||||
return this.root;
|
return this.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Composite getParent() {
|
public Composite getParent() {
|
||||||
return this.parent;
|
return this.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageContext copy() {
|
public PageContext copy() {
|
||||||
return copyOf(this.parent);
|
return copyOf(this.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageContext copyOf(final Composite parent) {
|
public PageContext copyOf(final Composite parent) {
|
||||||
return new PageContextImpl(
|
return new PageContextImpl(
|
||||||
this.i18nSupport,
|
this.i18nSupport,
|
||||||
this.composerService,
|
this.composerService,
|
||||||
this.root,
|
this.root,
|
||||||
parent,
|
parent,
|
||||||
new HashMap<>(this.attributes));
|
new HashMap<>(this.attributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageContext copyOfAttributes(final PageContext otherContext) {
|
public PageContext copyOfAttributes(final PageContext otherContext) {
|
||||||
final Map<String, String> attrs = new HashMap<>();
|
final Map<String, String> attrs = new HashMap<>();
|
||||||
attrs.putAll(this.attributes);
|
attrs.putAll(this.attributes);
|
||||||
attrs.putAll(((PageContextImpl) otherContext).attributes);
|
attrs.putAll(((PageContextImpl) otherContext).attributes);
|
||||||
return new PageContextImpl(
|
return new PageContextImpl(
|
||||||
this.i18nSupport,
|
this.i18nSupport,
|
||||||
this.composerService,
|
this.composerService,
|
||||||
this.root,
|
this.root,
|
||||||
this.parent,
|
this.parent,
|
||||||
attrs);
|
attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageContext withAttribute(final String key, final String value) {
|
public PageContext withAttribute(final String key, final String value) {
|
||||||
final Map<String, String> attrs = new HashMap<>();
|
final Map<String, String> attrs = new HashMap<>(this.attributes);
|
||||||
attrs.putAll(this.attributes);
|
attrs.put(key, value);
|
||||||
attrs.put(key, value);
|
return new PageContextImpl(
|
||||||
return new PageContextImpl(
|
this.i18nSupport,
|
||||||
this.i18nSupport,
|
this.composerService,
|
||||||
this.composerService,
|
this.root,
|
||||||
this.root,
|
this.parent,
|
||||||
this.parent,
|
attrs);
|
||||||
attrs);
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public String getAttribute(final String name) {
|
||||||
public String getAttribute(final String name) {
|
return this.attributes.get(name);
|
||||||
return this.attributes.get(name);
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public String getAttribute(final String name, final String def) {
|
||||||
public String getAttribute(final String name, final String def) {
|
return this.attributes.getOrDefault(name, def);
|
||||||
if (this.attributes.containsKey(name)) {
|
}
|
||||||
return this.attributes.get(name);
|
|
||||||
} else {
|
@Override
|
||||||
return def;
|
public boolean isReadonly() {
|
||||||
}
|
return BooleanUtils.toBoolean(getAttribute(AttributeKeys.READ_ONLY, "true"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReadonly() {
|
public EntityKey getEntityKey() {
|
||||||
return BooleanUtils.toBoolean(getAttribute(AttributeKeys.READ_ONLY, "true"));
|
if (hasAttribute(AttributeKeys.ENTITY_ID) && hasAttribute(AttributeKeys.ENTITY_TYPE)) {
|
||||||
}
|
return new EntityKey(
|
||||||
|
getAttribute(AttributeKeys.ENTITY_ID),
|
||||||
@Override
|
EntityType.valueOf(getAttribute(AttributeKeys.ENTITY_TYPE)));
|
||||||
public EntityKey getEntityKey() {
|
}
|
||||||
if (hasAttribute(AttributeKeys.ENTITY_ID) && hasAttribute(AttributeKeys.ENTITY_TYPE)) {
|
|
||||||
return new EntityKey(
|
return null;
|
||||||
getAttribute(AttributeKeys.ENTITY_ID),
|
}
|
||||||
EntityType.valueOf(getAttribute(AttributeKeys.ENTITY_TYPE)));
|
|
||||||
}
|
@Override
|
||||||
|
public EntityKey getParentEntityKey() {
|
||||||
return null;
|
if (hasAttribute(AttributeKeys.PARENT_ENTITY_ID) && hasAttribute(AttributeKeys.PARENT_ENTITY_TYPE)) {
|
||||||
}
|
return new EntityKey(
|
||||||
|
getAttribute(AttributeKeys.PARENT_ENTITY_ID),
|
||||||
@Override
|
EntityType.valueOf(getAttribute(AttributeKeys.PARENT_ENTITY_TYPE)));
|
||||||
public EntityKey getParentEntityKey() {
|
}
|
||||||
if (hasAttribute(AttributeKeys.PARENT_ENTITY_ID) && hasAttribute(AttributeKeys.PARENT_ENTITY_TYPE)) {
|
|
||||||
return new EntityKey(
|
return null;
|
||||||
getAttribute(AttributeKeys.PARENT_ENTITY_ID),
|
}
|
||||||
EntityType.valueOf(getAttribute(AttributeKeys.PARENT_ENTITY_TYPE)));
|
|
||||||
}
|
@Override
|
||||||
|
public PageContext withEntityKey(final EntityKey entityKey) {
|
||||||
return null;
|
if (entityKey == null) {
|
||||||
}
|
return removeAttribute(AttributeKeys.ENTITY_ID)
|
||||||
|
.removeAttribute(AttributeKeys.ENTITY_TYPE);
|
||||||
@Override
|
}
|
||||||
public PageContext withEntityKey(final EntityKey entityKey) {
|
return withAttribute(AttributeKeys.ENTITY_ID, entityKey.modelId)
|
||||||
if (entityKey == null) {
|
.withAttribute(AttributeKeys.ENTITY_TYPE, entityKey.entityType.name());
|
||||||
return removeAttribute(AttributeKeys.ENTITY_ID)
|
}
|
||||||
.removeAttribute(AttributeKeys.ENTITY_TYPE);
|
|
||||||
}
|
@Override
|
||||||
return withAttribute(AttributeKeys.ENTITY_ID, entityKey.modelId)
|
public PageContext withParentEntityKey(final EntityKey entityKey) {
|
||||||
.withAttribute(AttributeKeys.ENTITY_TYPE, entityKey.entityType.name());
|
if (entityKey == null) {
|
||||||
}
|
return removeAttribute(AttributeKeys.PARENT_ENTITY_ID)
|
||||||
|
.removeAttribute(AttributeKeys.PARENT_ENTITY_TYPE);
|
||||||
@Override
|
}
|
||||||
public PageContext withParentEntityKey(final EntityKey entityKey) {
|
return withAttribute(AttributeKeys.PARENT_ENTITY_ID, entityKey.modelId)
|
||||||
if (entityKey == null) {
|
.withAttribute(AttributeKeys.PARENT_ENTITY_TYPE, entityKey.entityType.name());
|
||||||
return removeAttribute(AttributeKeys.PARENT_ENTITY_ID)
|
}
|
||||||
.removeAttribute(AttributeKeys.PARENT_ENTITY_TYPE);
|
|
||||||
}
|
@Override
|
||||||
return withAttribute(AttributeKeys.PARENT_ENTITY_ID, entityKey.modelId)
|
public PageContext clearEntityKeys() {
|
||||||
.withAttribute(AttributeKeys.PARENT_ENTITY_TYPE, entityKey.entityType.name());
|
return withEntityKey(null)
|
||||||
}
|
.withParentEntityKey(null);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public PageContext clearEntityKeys() {
|
@Override
|
||||||
return withEntityKey(null)
|
public boolean hasAttribute(final String name) {
|
||||||
.withParentEntityKey(null);
|
return this.attributes.containsKey(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAttribute(final String name) {
|
public PageContext removeAttribute(final String name) {
|
||||||
return this.attributes.containsKey(name);
|
final Map<String, String> attrs = new HashMap<>(this.attributes);
|
||||||
}
|
attrs.remove(name);
|
||||||
|
return new PageContextImpl(
|
||||||
@Override
|
this.i18nSupport,
|
||||||
public PageContext removeAttribute(final String name) {
|
this.composerService,
|
||||||
final Map<String, String> attrs = new HashMap<>();
|
this.root,
|
||||||
attrs.putAll(this.attributes);
|
this.parent,
|
||||||
attrs.remove(name);
|
attrs);
|
||||||
return new PageContextImpl(
|
}
|
||||||
this.i18nSupport,
|
|
||||||
this.composerService,
|
@Override
|
||||||
this.root,
|
public PageContext clearAttributes() {
|
||||||
this.parent,
|
return new PageContextImpl(
|
||||||
attrs);
|
this.i18nSupport,
|
||||||
}
|
this.composerService,
|
||||||
|
this.root,
|
||||||
@Override
|
this.parent,
|
||||||
public PageContext clearAttributes() {
|
null);
|
||||||
return new PageContextImpl(
|
}
|
||||||
this.i18nSupport,
|
|
||||||
this.composerService,
|
@Override
|
||||||
this.root,
|
public void applyConfirmDialog(final LocTextKey confirmMessage, final Consumer<Boolean> callback) {
|
||||||
this.parent,
|
final Message messageBox = new Message(
|
||||||
null);
|
this.root.getShell(),
|
||||||
}
|
this.i18nSupport.getText("sebserver.dialog.confirm.title"),
|
||||||
|
this.i18nSupport.getText(confirmMessage),
|
||||||
@Override
|
SWT.OK | SWT.CANCEL,
|
||||||
public void applyConfirmDialog(final LocTextKey confirmMessage, final Consumer<Boolean> callback) {
|
this.i18nSupport);
|
||||||
final Message messageBox = new Message(
|
messageBox.setMarkupEnabled(true);
|
||||||
this.root.getShell(),
|
messageBox.open(new ConfirmDialogCallback(callback));
|
||||||
this.i18nSupport.getText("sebserver.dialog.confirm.title"),
|
}
|
||||||
this.i18nSupport.getText(confirmMessage),
|
|
||||||
SWT.OK | SWT.CANCEL,
|
@Override
|
||||||
this.i18nSupport);
|
public void forwardToPage(final PageDefinition pageDefinition) {
|
||||||
messageBox.setMarkupEnabled(true);
|
this.composerService.compose(
|
||||||
messageBox.open(new ConfirmDialogCallback(callback));
|
pageDefinition.composer(),
|
||||||
}
|
pageDefinition.applyPageContext(copyOf(this.root)));
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public void forwardToPage(final PageDefinition pageDefinition) {
|
@Override
|
||||||
this.composerService.compose(
|
public void forwardToMainPage() {
|
||||||
pageDefinition.composer(),
|
forwardToPage(this.composerService.mainPage());
|
||||||
pageDefinition.applyPageContext(copyOf(this.root)));
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void forwardToLoginPage() {
|
||||||
public void forwardToMainPage() {
|
this.clearAttributes()
|
||||||
forwardToPage(this.composerService.mainPage());
|
.forwardToPage(this.composerService.loginPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forwardToLoginPage() {
|
public void publishPageMessage(final LocTextKey title, final LocTextKey message) {
|
||||||
this.clearAttributes()
|
final MessageBox messageBox = new Message(
|
||||||
.forwardToPage(this.composerService.loginPage());
|
getShell(),
|
||||||
}
|
(title != null)
|
||||||
|
? this.i18nSupport.getText(title)
|
||||||
@Override
|
: "",
|
||||||
public void publishPageMessage(final LocTextKey title, final LocTextKey message) {
|
this.i18nSupport.getText(message),
|
||||||
final MessageBox messageBox = new Message(
|
SWT.NONE,
|
||||||
getShell(),
|
this.i18nSupport);
|
||||||
(title != null)
|
|
||||||
? this.i18nSupport.getText(title)
|
messageBox.setMarkupEnabled(true);
|
||||||
: "",
|
messageBox.open(null);
|
||||||
this.i18nSupport.getText(message),
|
}
|
||||||
SWT.NONE,
|
|
||||||
this.i18nSupport);
|
@Override
|
||||||
|
public void publishPageMessage(final PageMessageException pme) {
|
||||||
messageBox.setMarkupEnabled(true);
|
final MessageBox messageBox = new Message(
|
||||||
messageBox.open(null);
|
getShell(),
|
||||||
}
|
this.i18nSupport.getText("sebserver.page.message"),
|
||||||
|
this.i18nSupport.getText(pme.getMessageKey()),
|
||||||
@Override
|
SWT.NONE,
|
||||||
public void publishPageMessage(final PageMessageException pme) {
|
this.i18nSupport);
|
||||||
final MessageBox messageBox = new Message(
|
messageBox.setMarkupEnabled(true);
|
||||||
getShell(),
|
messageBox.open(null);
|
||||||
this.i18nSupport.getText("sebserver.page.message"),
|
}
|
||||||
this.i18nSupport.getText(pme.getMessageKey()),
|
|
||||||
SWT.NONE,
|
@Override
|
||||||
this.i18nSupport);
|
public void notifyError(final LocTextKey message, final Exception error) {
|
||||||
messageBox.setMarkupEnabled(true);
|
|
||||||
messageBox.open(null);
|
log.error("Unexpected GUI error notified: {}", error.getMessage());
|
||||||
}
|
|
||||||
|
final String errorMessage = message != null
|
||||||
@Override
|
? this.i18nSupport.getText(message)
|
||||||
public void notifyError(final LocTextKey message, final Exception error) {
|
: error.getMessage();
|
||||||
|
|
||||||
log.error("Unexpected GUI error notified: {}", error.getMessage());
|
if (error instanceof APIMessageError) {
|
||||||
|
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
|
||||||
final String errorMessage = message != null
|
final MessageBox messageBox = new Message(
|
||||||
? this.i18nSupport.getText(message)
|
getShell(),
|
||||||
: error.getMessage();
|
this.i18nSupport.getText("sebserver.error.unexpected"),
|
||||||
|
APIMessage.toHTML(errorMessage, errorMessages),
|
||||||
if (error instanceof APIMessageError) {
|
SWT.ERROR,
|
||||||
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
|
this.i18nSupport);
|
||||||
final MessageBox messageBox = new Message(
|
messageBox.setMarkupEnabled(true);
|
||||||
getShell(),
|
messageBox.open(null);
|
||||||
this.i18nSupport.getText("sebserver.error.unexpected"),
|
return;
|
||||||
APIMessage.toHTML(errorMessage, errorMessages),
|
}
|
||||||
SWT.ERROR,
|
|
||||||
this.i18nSupport);
|
final MessageBox messageBox = new Message(
|
||||||
messageBox.setMarkupEnabled(true);
|
getShell(),
|
||||||
messageBox.open(null);
|
this.i18nSupport.getText("sebserver.error.unexpected"),
|
||||||
return;
|
Utils.formatHTMLLines(errorMessage + "<br/><br/> Cause: " + error.getMessage()),
|
||||||
}
|
SWT.ERROR,
|
||||||
|
this.i18nSupport);
|
||||||
final MessageBox messageBox = new Message(
|
messageBox.open(null);
|
||||||
getShell(),
|
}
|
||||||
this.i18nSupport.getText("sebserver.error.unexpected"),
|
|
||||||
Utils.formatHTMLLines(errorMessage + "<br/><br/> Cause: " + error.getMessage()),
|
@Override
|
||||||
SWT.ERROR,
|
public String toString() {
|
||||||
this.i18nSupport);
|
return "PageContextImpl [root=" + this.root + ", parent=" + this.parent + ", attributes=" + this.attributes
|
||||||
messageBox.open(null);
|
+ "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static final class ConfirmDialogCallback implements DialogCallback {
|
||||||
public String toString() {
|
private static final long serialVersionUID = 1491270214433492441L;
|
||||||
return "PageContextImpl [root=" + this.root + ", parent=" + this.parent + ", attributes=" + this.attributes
|
private final Consumer<Boolean> onOK;
|
||||||
+ "]";
|
|
||||||
}
|
private ConfirmDialogCallback(final Consumer<Boolean> onOK) {
|
||||||
|
this.onOK = onOK;
|
||||||
private static final class ConfirmDialogCallback implements DialogCallback {
|
}
|
||||||
private static final long serialVersionUID = 1491270214433492441L;
|
|
||||||
private final Consumer<Boolean> onOK;
|
@Override
|
||||||
|
public void dialogClosed(final int returnCode) {
|
||||||
private ConfirmDialogCallback(final Consumer<Boolean> onOK) {
|
if (returnCode == SWT.OK) {
|
||||||
this.onOK = onOK;
|
try {
|
||||||
}
|
this.onOK.accept(true);
|
||||||
|
} catch (final Exception e) {
|
||||||
@Override
|
log.error(
|
||||||
public void dialogClosed(final int returnCode) {
|
"Unexpected on confirm callback execution. This should not happen, please secure the given onOK Runnable",
|
||||||
if (returnCode == SWT.OK) {
|
e);
|
||||||
try {
|
this.onOK.accept(false);
|
||||||
this.onOK.accept(true);
|
}
|
||||||
} catch (final Exception e) {
|
} else {
|
||||||
log.error(
|
this.onOK.accept(false);
|
||||||
"Unexpected on confirm callback execution. This should not happen, plase secure the given onOK Runnable",
|
}
|
||||||
e);
|
}
|
||||||
this.onOK.accept(false);
|
}
|
||||||
}
|
|
||||||
} else {
|
}
|
||||||
this.onOK.accept(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ public class PageServiceImpl implements PageService {
|
||||||
final int dependencies = (int) entities.stream()
|
final int dependencies = (int) entities.stream()
|
||||||
.flatMap(entity -> {
|
.flatMap(entity -> {
|
||||||
final RestCall<Set<EntityKey>>.RestCallBuilder builder =
|
final RestCall<Set<EntityKey>>.RestCallBuilder builder =
|
||||||
restService.<Set<EntityKey>>getBuilder(
|
restService.getBuilder(
|
||||||
entity.entityType(),
|
entity.entityType(),
|
||||||
CallType.GET_DEPENDENCIES);
|
CallType.GET_DEPENDENCIES);
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ public class PageServiceImpl implements PageService {
|
||||||
final boolean logoutSuccessful = this.currentUser.logout();
|
final boolean logoutSuccessful = this.currentUser.logout();
|
||||||
|
|
||||||
if (!logoutSuccessful) {
|
if (!logoutSuccessful) {
|
||||||
log.warn("Failed to logout. See logfiles for more information");
|
log.warn("Failed to logout. See log-files for more information");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
|
|
@ -1,104 +1,104 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.push;
|
package ch.ethz.seb.sebserver.gui.service.push;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.eclipse.rap.rwt.service.ServerPushSession;
|
import org.eclipse.rap.rwt.service.ServerPushSession;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/** Puts RAP's server-push functionality in a well defined service by using a context
|
/** Puts RAP's server-push functionality in a well defined service by using a context
|
||||||
* as state holder and the possibility to split the server-push process into two
|
* as state holder and the possibility to split the server-push process into two
|
||||||
* separated processes, a business-process to get and update business data and the
|
* separated processes, a business-process to get and update business data and the
|
||||||
* an update-process to update the UI after according to updated data */
|
* an update-process to update the UI after according to updated data */
|
||||||
@Lazy
|
@Lazy
|
||||||
@Service
|
@Service
|
||||||
public class ServerPushService {
|
public class ServerPushService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ServerPushService.class);
|
private static final Logger log = LoggerFactory.getLogger(ServerPushService.class);
|
||||||
|
|
||||||
public void runServerPush(
|
public void runServerPush(
|
||||||
final ServerPushContext context,
|
final ServerPushContext context,
|
||||||
final long intervalPause,
|
final long intervalPause,
|
||||||
final Consumer<ServerPushContext> update) {
|
final Consumer<ServerPushContext> update) {
|
||||||
|
|
||||||
this.runServerPush(context, intervalPause, null, update);
|
this.runServerPush(context, intervalPause, null, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void runServerPush(
|
public void runServerPush(
|
||||||
final ServerPushContext context,
|
final ServerPushContext context,
|
||||||
final long intervalPause,
|
final long intervalPause,
|
||||||
final Consumer<ServerPushContext> business,
|
final Consumer<ServerPushContext> business,
|
||||||
final Consumer<ServerPushContext> update) {
|
final Consumer<ServerPushContext> update) {
|
||||||
|
|
||||||
final ServerPushSession pushSession = new ServerPushSession();
|
final ServerPushSession pushSession = new ServerPushSession();
|
||||||
|
|
||||||
pushSession.start();
|
pushSession.start();
|
||||||
final Thread bgThread = new Thread(() -> {
|
final Thread bgThread = new Thread(() -> {
|
||||||
while (!context.isDisposed() && context.runAgain()) {
|
while (!context.isDisposed() && context.runAgain()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(intervalPause);
|
Thread.sleep(intervalPause);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("unexpected error while sleep: ", e);
|
log.debug("unexpected error while sleep: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (business != null) {
|
if (business != null) {
|
||||||
try {
|
try {
|
||||||
log.trace("Call business on Server Push Session on: {}", Thread.currentThread().getName());
|
log.trace("Call business on Server Push Session on: {}", Thread.currentThread().getName());
|
||||||
business.accept(context);
|
business.accept(context);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Unexpected error while do business for server push service", e);
|
log.error("Unexpected error while do business for server push service", e);
|
||||||
if (context.runAgain()) {
|
if (context.runAgain()) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.isDisposed()) {
|
if (!context.isDisposed()) {
|
||||||
|
|
||||||
log.trace("Call update on Server Push Session on: {}", Thread.currentThread().getName());
|
log.trace("Call update on Server Push Session on: {}", Thread.currentThread().getName());
|
||||||
|
|
||||||
context.getDisplay().asyncExec(() -> {
|
context.getDisplay().asyncExec(() -> {
|
||||||
try {
|
try {
|
||||||
update.accept(context);
|
update.accept(context);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Failed to update on Server Push Session {}. It seems that the UISession is not available anymore. "
|
"Failed to update on Server Push Session {}. It seems that the UISession is not available anymore. "
|
||||||
+ "This may source from a connection interruption.",
|
+ "This may source from a connection interruption. cause: {}",
|
||||||
Thread.currentThread().getName(), e.getMessage());
|
Thread.currentThread().getName(), e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Stop Server Push Session on: {}", Thread.currentThread().getName());
|
log.info("Stop Server Push Session on: {}", Thread.currentThread().getName());
|
||||||
try {
|
try {
|
||||||
pushSession.stop();
|
pushSession.stop();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Failed to stop Server Push Session on: {}. It seems that the UISession is not available anymore. This may source from a connection interruption",
|
"Failed to stop Server Push Session on: {}. It seems that the UISession is not available anymore. This may source from a connection interruption",
|
||||||
Thread.currentThread().getName(), e);
|
Thread.currentThread().getName(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
log.info("Start new Server Push Session on: {}", bgThread.getName());
|
log.info("Start new Server Push Session on: {}", bgThread.getName());
|
||||||
|
|
||||||
bgThread.setDaemon(true);
|
bgThread.setDaemon(true);
|
||||||
bgThread.start();
|
bgThread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,119 +1,116 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
||||||
|
|
||||||
import java.io.IOException;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import java.util.Collection;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import java.util.Map;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import java.util.function.Function;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import java.util.stream.Collectors;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
|
import org.eclipse.rap.rwt.service.ServiceHandler;
|
||||||
import javax.servlet.ServletException;
|
import org.slf4j.Logger;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import org.slf4j.LoggerFactory;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.eclipse.rap.rwt.service.ServiceHandler;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import org.slf4j.Logger;
|
import java.util.Collection;
|
||||||
import org.slf4j.LoggerFactory;
|
import java.util.Map;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import java.util.function.Function;
|
||||||
import org.springframework.stereotype.Service;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
/** Implements a eclipse RAP ServiceHandler to handle downloads */
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
@Lazy
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
@Service
|
||||||
|
@GuiProfile
|
||||||
@Lazy
|
public class DownloadService implements ServiceHandler {
|
||||||
@Service
|
|
||||||
@GuiProfile
|
private static final Logger log = LoggerFactory.getLogger(DownloadService.class);
|
||||||
public class DownloadService implements ServiceHandler {
|
|
||||||
|
public static final String DOWNLOAD_SERVICE_NAME = "DOWNLOAD_SERVICE";
|
||||||
private static final Logger log = LoggerFactory.getLogger(DownloadService.class);
|
public static final String HANDLER_NAME_PARAMETER = "download-handler-name";
|
||||||
|
public static final String DOWNLOAD_FILE_NAME = "download-file-name";
|
||||||
public static final String DOWNLOAD_SERVICE_NAME = "DOWNLOAD_SERVICE";
|
|
||||||
public static final String HANDLER_NAME_PARAMETER = "download-handler-name";
|
private final Map<String, DownloadServiceHandler> handler;
|
||||||
public static final String DOWNLOAD_FILE_NAME = "download-file-name";
|
|
||||||
|
protected DownloadService(final Collection<DownloadServiceHandler> handler) {
|
||||||
private final Map<String, DownloadServiceHandler> handler;
|
this.handler = handler
|
||||||
|
.stream()
|
||||||
protected DownloadService(final Collection<DownloadServiceHandler> handler) {
|
.collect(Collectors.toMap(
|
||||||
this.handler = handler
|
h -> h.getClass().getSimpleName(),
|
||||||
.stream()
|
Function.identity()));
|
||||||
.collect(Collectors.toMap(
|
}
|
||||||
h -> h.getClass().getSimpleName(),
|
|
||||||
Function.identity()));
|
@Override
|
||||||
}
|
public void service(
|
||||||
|
final HttpServletRequest request,
|
||||||
@Override
|
final HttpServletResponse response) {
|
||||||
public void service(
|
|
||||||
final HttpServletRequest request,
|
log.debug("Received download service request: {}", request.getRequestURI());
|
||||||
final HttpServletResponse response) throws IOException, ServletException {
|
|
||||||
|
final String handlerName = request.getParameter(HANDLER_NAME_PARAMETER);
|
||||||
log.debug("Received download service request: {}", request.getRequestURI());
|
if (StringUtils.isBlank(handlerName)) {
|
||||||
|
log.error("Missing request parameter {}. Ignoring download service request",
|
||||||
final String handlerName = request.getParameter(HANDLER_NAME_PARAMETER);
|
HANDLER_NAME_PARAMETER);
|
||||||
if (StringUtils.isBlank(handlerName)) {
|
return;
|
||||||
log.error("Missing request parameter {}. Ignoring download service request",
|
}
|
||||||
HANDLER_NAME_PARAMETER);
|
|
||||||
return;
|
if (!this.handler.containsKey(handlerName)) {
|
||||||
}
|
log.error("Missing DownloadServiceHandler with name {}. Ignoring download service request",
|
||||||
|
handlerName);
|
||||||
if (!this.handler.containsKey(handlerName)) {
|
return;
|
||||||
log.error("Missing DownloadServiceHandler with name {}. Ignoring download service request",
|
}
|
||||||
handlerName);
|
|
||||||
return;
|
this.handler
|
||||||
}
|
.get(handlerName)
|
||||||
|
.processDownload(request, response);
|
||||||
this.handler
|
}
|
||||||
.get(handlerName)
|
|
||||||
.processDownload(request, response);
|
public String createDownloadURL(
|
||||||
}
|
final String modelId,
|
||||||
|
final Class<? extends DownloadServiceHandler> handlerClass,
|
||||||
public String createDownloadURL(
|
final String downloadFileName) {
|
||||||
final String modelId,
|
|
||||||
final Class<? extends DownloadServiceHandler> handlerClass,
|
return createDownloadURL(modelId, null, handlerClass, downloadFileName);
|
||||||
final String downloadFileName) {
|
}
|
||||||
|
|
||||||
return createDownloadURL(modelId, null, handlerClass, downloadFileName);
|
public String createDownloadURL(
|
||||||
}
|
final String modelId,
|
||||||
|
final String parentModelId,
|
||||||
public String createDownloadURL(
|
final Class<? extends DownloadServiceHandler> handlerClass,
|
||||||
final String modelId,
|
final String downloadFileName) {
|
||||||
final String parentModelId,
|
|
||||||
final Class<? extends DownloadServiceHandler> handlerClass,
|
final StringBuilder url = new StringBuilder()
|
||||||
final String downloadFileName) {
|
.append(RWT.getServiceManager()
|
||||||
|
.getServiceHandlerUrl(DownloadService.DOWNLOAD_SERVICE_NAME))
|
||||||
final StringBuilder url = new StringBuilder()
|
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
||||||
.append(RWT.getServiceManager()
|
.append(API.PARAM_MODEL_ID)
|
||||||
.getServiceHandlerUrl(DownloadService.DOWNLOAD_SERVICE_NAME))
|
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||||
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
.append(modelId)
|
||||||
.append(API.PARAM_MODEL_ID)
|
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
||||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
.append(DownloadService.HANDLER_NAME_PARAMETER)
|
||||||
.append(modelId)
|
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||||
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
.append(handlerClass.getSimpleName())
|
||||||
.append(DownloadService.HANDLER_NAME_PARAMETER)
|
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
||||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
.append(DownloadService.DOWNLOAD_FILE_NAME)
|
||||||
.append(handlerClass.getSimpleName())
|
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||||
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
.append(downloadFileName);
|
||||||
.append(DownloadService.DOWNLOAD_FILE_NAME)
|
|
||||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
if (StringUtils.isNotBlank(parentModelId)) {
|
||||||
.append(downloadFileName);
|
url.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
||||||
|
.append(API.PARAM_PARENT_MODEL_ID)
|
||||||
if (StringUtils.isNotBlank(parentModelId)) {
|
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||||
url.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
.append(parentModelId);
|
||||||
.append(API.PARAM_PARENT_MODEL_ID)
|
}
|
||||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
|
||||||
.append(parentModelId);
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return url.toString();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public interface DownloadServiceHandler {
|
/** Interface defining a service to handle downloads */
|
||||||
|
public interface DownloadServiceHandler {
|
||||||
void processDownload(final HttpServletRequest request, final HttpServletResponse response);
|
|
||||||
|
/** Process a requested download
|
||||||
}
|
*
|
||||||
|
* @param request The download HttpServletRequest
|
||||||
|
* @param response the response to send the download to */
|
||||||
|
void processDownload(final HttpServletRequest request, final HttpServletResponse response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,69 +1,69 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ExportClientConfig;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ExportClientConfig;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class SebClientConfigDownload extends AbstractDownloadServiceHandler {
|
public class SebClientConfigDownload extends AbstractDownloadServiceHandler {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SebClientConfigDownload.class);
|
private static final Logger log = LoggerFactory.getLogger(SebClientConfigDownload.class);
|
||||||
|
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
public final String downloadFileName;
|
public final String downloadFileName;
|
||||||
|
|
||||||
protected SebClientConfigDownload(
|
protected SebClientConfigDownload(
|
||||||
final RestService restService,
|
final RestService restService,
|
||||||
@Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) {
|
@Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) {
|
||||||
|
|
||||||
this.restService = restService;
|
this.restService = restService;
|
||||||
this.downloadFileName = downloadFileName;
|
this.downloadFileName = downloadFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void webserviceCall(final String modelId, final String parentModelId, final OutputStream downloadOut) {
|
protected void webserviceCall(final String modelId, final String parentModelId, final OutputStream downloadOut) {
|
||||||
|
|
||||||
final InputStream input = this.restService.getBuilder(ExportClientConfig.class)
|
final InputStream input = this.restService.getBuilder(ExportClientConfig.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
||||||
.call()
|
.call()
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IOUtils.copyLarge(input, downloadOut);
|
IOUtils.copyLarge(input, downloadOut);
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error(
|
log.error(
|
||||||
"Unexpected error while streaming incomming config data from web-service to output-stream of download response: ",
|
"Unexpected error while streaming incoming config data from web-service to output-stream of download response: ",
|
||||||
e);
|
e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
downloadOut.flush();
|
downloadOut.flush();
|
||||||
downloadOut.close();
|
downloadOut.close();
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error("Unexpected error while trying to close download output-stream");
|
log.error("Unexpected error while trying to close download output-stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ExportExamConfig;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ExportExamConfig;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class SebExamConfigDownload extends AbstractDownloadServiceHandler {
|
public class SebExamConfigDownload extends AbstractDownloadServiceHandler {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SebExamConfigDownload.class);
|
private static final Logger log = LoggerFactory.getLogger(SebExamConfigDownload.class);
|
||||||
|
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
|
|
||||||
protected SebExamConfigDownload(final RestService restService) {
|
protected SebExamConfigDownload(final RestService restService) {
|
||||||
this.restService = restService;
|
this.restService = restService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void webserviceCall(final String modelId, final String parentModelId, final OutputStream downloadOut) {
|
protected void webserviceCall(final String modelId, final String parentModelId, final OutputStream downloadOut) {
|
||||||
|
|
||||||
final InputStream input = this.restService.getBuilder(ExportExamConfig.class)
|
final InputStream input = this.restService.getBuilder(ExportExamConfig.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
||||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, parentModelId)
|
.withURIVariable(API.PARAM_PARENT_MODEL_ID, parentModelId)
|
||||||
.call()
|
.call()
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IOUtils.copyLarge(input, downloadOut);
|
IOUtils.copyLarge(input, downloadOut);
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error(
|
log.error(
|
||||||
"Unexpected error while streaming incomming config data from web-service to output-stream of download response: ",
|
"Unexpected error while streaming incoming config data from web-service to output-stream of download response: ",
|
||||||
e);
|
e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
downloadOut.flush();
|
downloadOut.flush();
|
||||||
downloadOut.close();
|
downloadOut.close();
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error("Unexpected error while trying to close download output-stream");
|
log.error("Unexpected error while trying to close download output-stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,63 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
package ch.ethz.seb.sebserver.gui.service.remote.download;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportPlainXML;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportPlainXML;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class SebExamConfigPlaintextDownload extends AbstractDownloadServiceHandler {
|
public class SebExamConfigPlaintextDownload extends AbstractDownloadServiceHandler {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPlaintextDownload.class);
|
private static final Logger log = LoggerFactory.getLogger(SebExamConfigPlaintextDownload.class);
|
||||||
|
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
|
|
||||||
protected SebExamConfigPlaintextDownload(final RestService restService) {
|
protected SebExamConfigPlaintextDownload(final RestService restService) {
|
||||||
this.restService = restService;
|
this.restService = restService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void webserviceCall(final String modelId, final String parentModelId, final OutputStream downloadOut) {
|
protected void webserviceCall(final String modelId, final String parentModelId, final OutputStream downloadOut) {
|
||||||
|
|
||||||
final InputStream input = this.restService.getBuilder(ExportPlainXML.class)
|
final InputStream input = this.restService.getBuilder(ExportPlainXML.class)
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
||||||
.call()
|
.call()
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IOUtils.copyLarge(input, downloadOut);
|
IOUtils.copyLarge(input, downloadOut);
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error(
|
log.error(
|
||||||
"Unexpected error while streaming incomming config data from web-service to output-stream of download response: ",
|
"Unexpected error while streaming incoming config data from web-service to output-stream of download response: ",
|
||||||
e);
|
e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
downloadOut.flush();
|
downloadOut.flush();
|
||||||
downloadOut.close();
|
downloadOut.close();
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
log.error("Unexpected error while trying to close download output-stream");
|
log.error("Unexpected error while trying to close download output-stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,45 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.client.ClientHttpRequest;
|
import org.springframework.http.client.ClientHttpRequest;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
public abstract class AbstractExportCall extends RestCall<InputStream> {
|
public abstract class AbstractExportCall extends RestCall<InputStream> {
|
||||||
|
|
||||||
protected AbstractExportCall(
|
protected AbstractExportCall(
|
||||||
final TypeKey<InputStream> typeKey,
|
final TypeKey<InputStream> typeKey,
|
||||||
final HttpMethod httpMethod,
|
final HttpMethod httpMethod,
|
||||||
final MediaType contentType,
|
final MediaType contentType,
|
||||||
final String path) {
|
final String path) {
|
||||||
|
|
||||||
super(typeKey, httpMethod, contentType, path);
|
super(typeKey, httpMethod, contentType, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Result<InputStream> exchange(final RestCallBuilder builder) {
|
protected Result<InputStream> exchange(final RestCallBuilder builder) {
|
||||||
|
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> builder
|
||||||
|
.getRestTemplate()
|
||||||
return builder
|
.execute(
|
||||||
.getRestTemplate()
|
builder.buildURI(),
|
||||||
.execute(
|
this.httpMethod,
|
||||||
builder.buildURI(),
|
(final ClientHttpRequest requestCallback) -> {
|
||||||
this.httpMethod,
|
},
|
||||||
(final ClientHttpRequest requestCallback) -> {
|
response -> IOUtils.toBufferedInputStream(response.getBody()),
|
||||||
},
|
builder.getURIVariables()));
|
||||||
response -> IOUtils.toBufferedInputStream(response.getBody()),
|
}
|
||||||
builder.getURIVariables());
|
|
||||||
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
||||||
|
|
||||||
public interface FormBinding {
|
/** Defines a form binding to get form parameter and values either in JSON format
|
||||||
|
* or as form-url-encoded string */
|
||||||
String getFormAsJson();
|
public interface FormBinding {
|
||||||
|
|
||||||
String getFormUrlEncoded();
|
/** Get the form parameter and values in JSON format
|
||||||
|
*
|
||||||
}
|
* @return the form parameter and values in JSON format */
|
||||||
|
String getFormAsJson();
|
||||||
|
|
||||||
|
/** Get the form parameter and values in form-url-encoded string format.
|
||||||
|
*
|
||||||
|
* @return the form parameter and values in form-url-encoded string format.*/
|
||||||
|
String getFormUrlEncoded();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,422 +1,420 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
||||||
|
|
||||||
import java.io.IOException;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import java.io.InputStream;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import java.util.Arrays;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import java.util.HashMap;
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import java.util.List;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
import java.util.Map;
|
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||||
import java.util.function.Function;
|
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import org.slf4j.Logger;
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
import org.slf4j.LoggerFactory;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import org.springframework.core.io.InputStreamResource;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.slf4j.Logger;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.client.RestClientResponseException;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
import com.fasterxml.jackson.core.JsonParseException;
|
import org.springframework.web.client.RestClientResponseException;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
|
||||||
|
import java.io.IOException;
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import java.io.InputStream;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import java.util.Arrays;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import java.util.HashMap;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
import java.util.List;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import java.util.Map;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
import java.util.function.Function;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
public abstract class RestCall<T> {
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RestCall.class);
|
||||||
public abstract class RestCall<T> {
|
|
||||||
|
public enum CallType {
|
||||||
private static final Logger log = LoggerFactory.getLogger(RestCall.class);
|
UNDEFINED,
|
||||||
|
GET_SINGLE,
|
||||||
public enum CallType {
|
GET_PAGE,
|
||||||
UNDEFINED,
|
GET_NAMES,
|
||||||
GET_SINGLE,
|
GET_DEPENDENCIES,
|
||||||
GET_PAGE,
|
GET_LIST,
|
||||||
GET_NAMES,
|
NEW,
|
||||||
GET_DEPENDENCIES,
|
REGISTER,
|
||||||
GET_LIST,
|
SAVE,
|
||||||
NEW,
|
DELETE,
|
||||||
REGISTER,
|
ACTIVATION_ACTIVATE,
|
||||||
SAVE,
|
ACTIVATION_DEACTIVATE
|
||||||
DELETE,
|
}
|
||||||
ACTIVATION_ACTIVATE,
|
|
||||||
ACTIVATION_DEACTIVATE
|
protected RestService restService;
|
||||||
}
|
protected JSONMapper jsonMapper;
|
||||||
|
protected TypeKey<T> typeKey;
|
||||||
protected RestService restService;
|
protected final HttpMethod httpMethod;
|
||||||
protected JSONMapper jsonMapper;
|
protected final MediaType contentType;
|
||||||
protected TypeKey<T> typeKey;
|
protected final String path;
|
||||||
protected final HttpMethod httpMethod;
|
|
||||||
protected final MediaType contentType;
|
protected RestCall(
|
||||||
protected final String path;
|
final TypeKey<T> typeKey,
|
||||||
|
final HttpMethod httpMethod,
|
||||||
protected RestCall(
|
final MediaType contentType,
|
||||||
final TypeKey<T> typeKey,
|
final String path) {
|
||||||
final HttpMethod httpMethod,
|
|
||||||
final MediaType contentType,
|
this.typeKey = typeKey;
|
||||||
final String path) {
|
this.httpMethod = httpMethod;
|
||||||
|
this.contentType = contentType;
|
||||||
this.typeKey = typeKey;
|
this.path = path;
|
||||||
this.httpMethod = httpMethod;
|
|
||||||
this.contentType = contentType;
|
}
|
||||||
this.path = path;
|
|
||||||
|
protected RestCall<T> init(
|
||||||
}
|
final RestService restService,
|
||||||
|
final JSONMapper jsonMapper) {
|
||||||
protected RestCall<T> init(
|
|
||||||
final RestService restService,
|
this.restService = restService;
|
||||||
final JSONMapper jsonMapper) {
|
this.jsonMapper = jsonMapper;
|
||||||
|
return this;
|
||||||
this.restService = restService;
|
}
|
||||||
this.jsonMapper = jsonMapper;
|
|
||||||
return this;
|
public EntityType getEntityType() {
|
||||||
}
|
if (this.typeKey != null) {
|
||||||
|
return this.typeKey.entityType;
|
||||||
public EntityType getEntityType() {
|
}
|
||||||
if (this.typeKey != null) {
|
|
||||||
return this.typeKey.entityType;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
protected Result<T> exchange(final RestCallBuilder builder) {
|
||||||
}
|
|
||||||
|
log.debug("Call webservice API on {} for {}", this.path, builder);
|
||||||
protected Result<T> exchange(final RestCallBuilder builder) {
|
|
||||||
|
try {
|
||||||
log.debug("Call webservice API on {} for {}", this.path, builder);
|
final ResponseEntity<String> responseEntity = builder.restTemplate
|
||||||
|
.exchange(
|
||||||
try {
|
builder.buildURI(),
|
||||||
final ResponseEntity<String> responseEntity = builder.restTemplate
|
this.httpMethod,
|
||||||
.exchange(
|
builder.buildRequestEntity(),
|
||||||
builder.buildURI(),
|
String.class,
|
||||||
this.httpMethod,
|
builder.uriVariables);
|
||||||
builder.buildRequestEntity(),
|
|
||||||
String.class,
|
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||||
builder.uriVariables);
|
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
log.trace("response body --> {}" + responseEntity.getBody());
|
||||||
|
}
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.trace("response body --> {}" + responseEntity.getBody());
|
if (!responseEntity.hasBody()) {
|
||||||
}
|
return Result.ofEmpty();
|
||||||
|
}
|
||||||
if (!responseEntity.hasBody()) {
|
|
||||||
return Result.ofEmpty();
|
return Result.of(RestCall.this.jsonMapper.readValue(
|
||||||
}
|
responseEntity.getBody(),
|
||||||
|
RestCall.this.typeKey.typeRef));
|
||||||
return Result.of(RestCall.this.jsonMapper.readValue(
|
|
||||||
responseEntity.getBody(),
|
} else {
|
||||||
RestCall.this.typeKey.typeRef));
|
return handleRestCallError(responseEntity);
|
||||||
|
}
|
||||||
} else {
|
} catch (final RestClientResponseException responseError) {
|
||||||
return handleRestCallError(responseEntity);
|
|
||||||
}
|
final RestCallError restCallError = new RestCallError("Unexpected error while rest call", responseError);
|
||||||
} catch (final RestClientResponseException responseError) {
|
try {
|
||||||
|
|
||||||
final RestCallError restCallError = new RestCallError("Unexpected error while rest call", responseError);
|
final String responseBody = responseError.getResponseBodyAsString();
|
||||||
try {
|
restCallError.errors.addAll(RestCall.this.jsonMapper.readValue(
|
||||||
|
responseBody,
|
||||||
final String responseBody = responseError.getResponseBodyAsString();
|
new TypeReference<List<APIMessage>>() {
|
||||||
restCallError.errors.addAll(RestCall.this.jsonMapper.readValue(
|
}));
|
||||||
responseBody,
|
|
||||||
new TypeReference<List<APIMessage>>() {
|
} catch (final IOException e) {
|
||||||
}));
|
restCallError.errors.add(APIMessage.ErrorMessage.UNEXPECTED.of(
|
||||||
|
responseError,
|
||||||
} catch (final IOException e) {
|
"NO RESPONSE AVAILABLE" + " cause: " + e.getMessage(),
|
||||||
restCallError.errors.add(APIMessage.ErrorMessage.UNEXPECTED.of(
|
String.valueOf(builder)));
|
||||||
responseError,
|
}
|
||||||
"NO RESPONSE AVAILABLE" + " cause: " + e.getMessage(),
|
|
||||||
String.valueOf(builder)));
|
return Result.ofError(restCallError);
|
||||||
}
|
} catch (final Exception e) {
|
||||||
|
final RestCallError restCallError = new RestCallError("Unexpected error while rest call", e);
|
||||||
return Result.ofError(restCallError);
|
restCallError.errors.add(APIMessage.ErrorMessage.UNEXPECTED.of(
|
||||||
} catch (final Exception e) {
|
e,
|
||||||
final RestCallError restCallError = new RestCallError("Unexpected error while rest call", e);
|
"NO RESPONSE AVAILABLE",
|
||||||
restCallError.errors.add(APIMessage.ErrorMessage.UNEXPECTED.of(
|
String.valueOf(builder)));
|
||||||
e,
|
return Result.ofError(e);
|
||||||
"NO RESPONSE AVAILABLE",
|
}
|
||||||
String.valueOf(builder)));
|
}
|
||||||
return Result.ofError(e);
|
|
||||||
}
|
public RestCallBuilder newBuilder() {
|
||||||
}
|
return new RestCallBuilder(
|
||||||
|
this.restService.getWebserviceAPIRestTemplate(),
|
||||||
public RestCallBuilder newBuilder() {
|
this.restService.getWebserviceURIBuilder());
|
||||||
return new RestCallBuilder(
|
}
|
||||||
this.restService.getWebserviceAPIRestTemplate(),
|
|
||||||
this.restService.getWebserviceURIBuilder());
|
public RestCall<T>.RestCallBuilder newBuilder(final RestCall<?>.RestCallBuilder builder) {
|
||||||
}
|
return new RestCallBuilder(builder);
|
||||||
|
}
|
||||||
public RestCall<T>.RestCallBuilder newBuilder(final RestCall<?>.RestCallBuilder builder) {
|
|
||||||
return new RestCallBuilder(builder);
|
private Result<T> handleRestCallError(final ResponseEntity<String> responseEntity)
|
||||||
}
|
throws IOException {
|
||||||
|
|
||||||
private Result<T> handleRestCallError(final ResponseEntity<String> responseEntity)
|
final RestCallError restCallError =
|
||||||
throws IOException, JsonParseException, JsonMappingException {
|
new RestCallError("Response Entity: " + responseEntity.toString());
|
||||||
|
|
||||||
final RestCallError restCallError =
|
try {
|
||||||
new RestCallError("Response Entity: " + responseEntity.toString());
|
restCallError.errors.addAll(RestCall.this.jsonMapper.readValue(
|
||||||
|
responseEntity.getBody(),
|
||||||
try {
|
new TypeReference<List<APIMessage>>() {
|
||||||
restCallError.errors.addAll(RestCall.this.jsonMapper.readValue(
|
}));
|
||||||
responseEntity.getBody(),
|
} catch (final JsonParseException jpe) {
|
||||||
new TypeReference<List<APIMessage>>() {
|
if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
|
||||||
}));
|
restCallError.errors.add(APIMessage.ErrorMessage.UNAUTHORIZED.of(responseEntity.getBody()));
|
||||||
} catch (final JsonParseException jpe) {
|
} else {
|
||||||
if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
|
restCallError.errors.add(APIMessage.ErrorMessage.GENERIC.of(responseEntity.getBody()));
|
||||||
restCallError.errors.add(APIMessage.ErrorMessage.UNAUTHORIZED.of(responseEntity.getBody()));
|
}
|
||||||
} else {
|
}
|
||||||
restCallError.errors.add(APIMessage.ErrorMessage.GENERIC.of(responseEntity.getBody()));
|
|
||||||
}
|
log.debug(
|
||||||
}
|
"Webservice answered with well defined error- or validation-failure-response: ",
|
||||||
|
restCallError);
|
||||||
log.debug(
|
|
||||||
"Webservice answered with well defined error- or validation-failure-response: ",
|
return Result.ofError(restCallError);
|
||||||
restCallError);
|
}
|
||||||
|
|
||||||
return Result.ofError(restCallError);
|
public class RestCallBuilder {
|
||||||
}
|
|
||||||
|
private RestTemplate restTemplate;
|
||||||
public class RestCallBuilder {
|
private UriComponentsBuilder uriComponentsBuilder;
|
||||||
|
private final HttpHeaders httpHeaders;
|
||||||
private RestTemplate restTemplate;
|
private String body = null;
|
||||||
private UriComponentsBuilder uriComponentsBuilder;
|
private InputStream streamingBody = null;
|
||||||
private final HttpHeaders httpHeaders;
|
|
||||||
private String body = null;
|
private final MultiValueMap<String, String> queryParams;
|
||||||
private InputStream streamingBody = null;
|
private final Map<String, String> uriVariables;
|
||||||
|
|
||||||
private final MultiValueMap<String, String> queryParams;
|
protected RestCallBuilder(final RestTemplate restTemplate, final UriComponentsBuilder uriComponentsBuilder) {
|
||||||
private final Map<String, String> uriVariables;
|
this.restTemplate = restTemplate;
|
||||||
|
this.uriComponentsBuilder = uriComponentsBuilder;
|
||||||
protected RestCallBuilder(final RestTemplate restTemplate, final UriComponentsBuilder uriComponentsBuilder) {
|
this.httpHeaders = new HttpHeaders();
|
||||||
this.restTemplate = restTemplate;
|
this.queryParams = new LinkedMultiValueMap<>();
|
||||||
this.uriComponentsBuilder = uriComponentsBuilder;
|
this.uriVariables = new HashMap<>();
|
||||||
this.httpHeaders = new HttpHeaders();
|
this.httpHeaders.set(
|
||||||
this.queryParams = new LinkedMultiValueMap<>();
|
HttpHeaders.CONTENT_TYPE,
|
||||||
this.uriVariables = new HashMap<>();
|
RestCall.this.contentType.toString());
|
||||||
this.httpHeaders.set(
|
}
|
||||||
HttpHeaders.CONTENT_TYPE,
|
|
||||||
RestCall.this.contentType.toString());
|
public RestCallBuilder(final RestCall<?>.RestCallBuilder builder) {
|
||||||
}
|
this.restTemplate = builder.restTemplate;
|
||||||
|
this.uriComponentsBuilder = builder.uriComponentsBuilder;
|
||||||
public RestCallBuilder(final RestCall<?>.RestCallBuilder builder) {
|
this.httpHeaders = builder.httpHeaders;
|
||||||
this.restTemplate = builder.restTemplate;
|
this.body = builder.body;
|
||||||
this.uriComponentsBuilder = builder.uriComponentsBuilder;
|
this.streamingBody = builder.streamingBody;
|
||||||
this.httpHeaders = builder.httpHeaders;
|
this.queryParams = new LinkedMultiValueMap<>(builder.queryParams);
|
||||||
this.body = builder.body;
|
this.uriVariables = new HashMap<>(builder.uriVariables);
|
||||||
this.queryParams = new LinkedMultiValueMap<>(builder.queryParams);
|
}
|
||||||
this.uriVariables = new HashMap<>(builder.uriVariables);
|
|
||||||
}
|
public RestTemplate getRestTemplate() {
|
||||||
|
return this.restTemplate;
|
||||||
public RestTemplate getRestTemplate() {
|
}
|
||||||
return this.restTemplate;
|
|
||||||
}
|
public RestCallBuilder withRestTemplate(final RestTemplate restTemplate) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
public RestCallBuilder withRestTemplate(final RestTemplate restTemplate) {
|
return this;
|
||||||
this.restTemplate = restTemplate;
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withUriComponentsBuilder(final UriComponentsBuilder uriComponentsBuilder) {
|
||||||
|
this.uriComponentsBuilder = uriComponentsBuilder;
|
||||||
public RestCallBuilder withUriComponentsBuilder(final UriComponentsBuilder uriComponentsBuilder) {
|
return this;
|
||||||
this.uriComponentsBuilder = uriComponentsBuilder;
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withHeaders(final HttpHeaders headers) {
|
||||||
|
this.httpHeaders.addAll(headers);
|
||||||
public RestCallBuilder withHeaders(final HttpHeaders headers) {
|
return this;
|
||||||
this.httpHeaders.addAll(headers);
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withHeader(final String name, final String value) {
|
||||||
|
this.httpHeaders.set(name, value);
|
||||||
public RestCallBuilder withHeader(final String name, final String value) {
|
return this;
|
||||||
this.httpHeaders.set(name, value);
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withHeaders(final MultiValueMap<String, String> params) {
|
||||||
|
this.httpHeaders.addAll(params);
|
||||||
public RestCallBuilder withHeaders(final MultiValueMap<String, String> params) {
|
return this;
|
||||||
this.httpHeaders.addAll(params);
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder apply(final Function<RestCallBuilder, RestCallBuilder> f) {
|
||||||
|
return f.apply(this);
|
||||||
public RestCallBuilder apply(final Function<RestCallBuilder, RestCallBuilder> f) {
|
}
|
||||||
return f.apply(this);
|
|
||||||
}
|
public RestCallBuilder withBody(final Object body) {
|
||||||
|
if (body == null) {
|
||||||
public RestCallBuilder withBody(final Object body) {
|
this.body = null;
|
||||||
if (body == null) {
|
return this;
|
||||||
this.body = null;
|
}
|
||||||
return this;
|
|
||||||
}
|
if (body instanceof String) {
|
||||||
|
this.body = String.valueOf(body);
|
||||||
if (body instanceof String) {
|
return this;
|
||||||
this.body = String.valueOf(body);
|
}
|
||||||
return this;
|
|
||||||
}
|
if (body instanceof InputStream) {
|
||||||
|
this.streamingBody = (InputStream) body;
|
||||||
if (body instanceof InputStream) {
|
return this;
|
||||||
this.streamingBody = (InputStream) body;
|
}
|
||||||
return this;
|
|
||||||
}
|
try {
|
||||||
|
this.body = RestCall.this.jsonMapper.writeValueAsString(body);
|
||||||
try {
|
} catch (final JsonProcessingException e) {
|
||||||
this.body = RestCall.this.jsonMapper.writeValueAsString(body);
|
log.error("Error while trying to parse body json object: " + body);
|
||||||
} catch (final JsonProcessingException e) {
|
}
|
||||||
log.error("Error while trying to parse body json object: " + body);
|
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withURIVariable(final String name, final String value) {
|
||||||
|
this.uriVariables.put(name, value);
|
||||||
public RestCallBuilder withURIVariable(final String name, final String value) {
|
return this;
|
||||||
this.uriVariables.put(name, value);
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withQueryParam(final String name, final String value) {
|
||||||
|
this.queryParams.put(name, Arrays.asList(value));
|
||||||
public RestCallBuilder withQueryParam(final String name, final String value) {
|
return this;
|
||||||
this.queryParams.put(name, Arrays.asList(value));
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withQueryParams(final MultiValueMap<String, String> params) {
|
||||||
|
if (params != null) {
|
||||||
public RestCallBuilder withQueryParams(final MultiValueMap<String, String> params) {
|
this.queryParams.putAll(params);
|
||||||
if (params != null) {
|
}
|
||||||
this.queryParams.putAll(params);
|
return this;
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withFormParam(final String name, final String value) {
|
||||||
|
final String encodedVal = Utils.encodeFormURL_UTF_8(value);
|
||||||
public RestCallBuilder withFormParam(final String name, final String value) {
|
if (StringUtils.isBlank(this.body)) {
|
||||||
final String encodedVal = Utils.encodeFormURL_UTF_8(value);
|
this.body = name + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR + encodedVal;
|
||||||
if (StringUtils.isBlank(this.body)) {
|
} else {
|
||||||
this.body = name + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR + encodedVal;
|
this.body = this.body + Constants.FORM_URL_ENCODED_SEPARATOR + name +
|
||||||
} else {
|
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR + encodedVal;
|
||||||
this.body = this.body + Constants.FORM_URL_ENCODED_SEPARATOR + name +
|
}
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR + encodedVal;
|
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withPaging(final int pageNumber, final int pageSize) {
|
||||||
|
this.queryParams.put(Page.ATTR_PAGE_NUMBER, Arrays.asList(String.valueOf(pageNumber)));
|
||||||
public RestCallBuilder withPaging(final int pageNumber, final int pageSize) {
|
this.queryParams.put(Page.ATTR_PAGE_SIZE, Arrays.asList(String.valueOf(pageSize)));
|
||||||
this.queryParams.put(Page.ATTR_PAGE_NUMBER, Arrays.asList(String.valueOf(pageNumber)));
|
return this;
|
||||||
this.queryParams.put(Page.ATTR_PAGE_SIZE, Arrays.asList(String.valueOf(pageSize)));
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withSorting(final String column, final PageSortOrder order) {
|
||||||
|
if (column != null) {
|
||||||
public RestCallBuilder withSorting(final String column, final PageSortOrder order) {
|
this.queryParams.put(Page.ATTR_SORT, Arrays.asList(order.encode(column)));
|
||||||
if (column != null) {
|
}
|
||||||
this.queryParams.put(Page.ATTR_SORT, Arrays.asList(order.encode(column)));
|
return this;
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
public RestCallBuilder withFormBinding(final FormBinding formBinding) {
|
||||||
|
if (RestCall.this.httpMethod == HttpMethod.PUT) {
|
||||||
public RestCallBuilder withFormBinding(final FormBinding formBinding) {
|
return withBody(formBinding.getFormAsJson());
|
||||||
if (RestCall.this.httpMethod == HttpMethod.PUT) {
|
} else {
|
||||||
return withBody(formBinding.getFormAsJson());
|
this.body = formBinding.getFormUrlEncoded();
|
||||||
} else {
|
return this;
|
||||||
this.body = formBinding.getFormUrlEncoded();
|
}
|
||||||
return this;
|
}
|
||||||
}
|
|
||||||
}
|
public RestCallBuilder onlyActive(final boolean active) {
|
||||||
|
this.queryParams.put(Entity.FILTER_ATTR_ACTIVE, Arrays.asList(String.valueOf(active)));
|
||||||
public RestCallBuilder onlyActive(final boolean active) {
|
return this;
|
||||||
this.queryParams.put(Entity.FILTER_ATTR_ACTIVE, Arrays.asList(String.valueOf(active)));
|
}
|
||||||
return this;
|
|
||||||
}
|
public final Result<T> call() {
|
||||||
|
return RestCall.this.exchange(this);
|
||||||
public final Result<T> call() {
|
}
|
||||||
return RestCall.this.exchange(this);
|
|
||||||
}
|
public String buildURI() {
|
||||||
|
return this.uriComponentsBuilder
|
||||||
public String buildURI() {
|
.cloneBuilder()
|
||||||
return this.uriComponentsBuilder
|
.path(RestCall.this.path)
|
||||||
.cloneBuilder()
|
.queryParams(this.queryParams)
|
||||||
.path(RestCall.this.path)
|
.toUriString();
|
||||||
.queryParams(this.queryParams)
|
}
|
||||||
.toUriString();
|
|
||||||
}
|
public HttpEntity<?> buildRequestEntity() {
|
||||||
|
if (this.streamingBody != null) {
|
||||||
public HttpEntity<?> buildRequestEntity() {
|
return new HttpEntity<>(new InputStreamResource(this.streamingBody), this.httpHeaders);
|
||||||
if (this.streamingBody != null) {
|
} else if (this.body != null) {
|
||||||
return new HttpEntity<>(new InputStreamResource(this.streamingBody), this.httpHeaders);
|
return new HttpEntity<>(this.body, this.httpHeaders);
|
||||||
} else if (this.body != null) {
|
} else {
|
||||||
return new HttpEntity<>(this.body, this.httpHeaders);
|
return new HttpEntity<>(this.httpHeaders);
|
||||||
} else {
|
}
|
||||||
return new HttpEntity<>(this.httpHeaders);
|
}
|
||||||
}
|
|
||||||
}
|
public Map<String, String> getURIVariables() {
|
||||||
|
return Utils.immutableMapOf(this.uriVariables);
|
||||||
public Map<String, String> getURIVariables() {
|
}
|
||||||
return Utils.immutableMapOf(this.uriVariables);
|
|
||||||
}
|
@Override
|
||||||
|
public String toString() {
|
||||||
@Override
|
return "RestCallBuilder [httpHeaders=" + this.httpHeaders + ", body=" + this.body + ", queryParams="
|
||||||
public String toString() {
|
+ this.queryParams
|
||||||
return "RestCallBuilder [httpHeaders=" + this.httpHeaders + ", body=" + this.body + ", queryParams="
|
+ ", uriVariables=" + this.uriVariables + "]";
|
||||||
+ this.queryParams
|
}
|
||||||
+ ", uriVariables=" + this.uriVariables + "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public static final class TypeKey<T> {
|
||||||
|
final CallType callType;
|
||||||
public static final class TypeKey<T> {
|
final EntityType entityType;
|
||||||
final CallType callType;
|
private final TypeReference<T> typeRef;
|
||||||
final EntityType entityType;
|
|
||||||
private final TypeReference<T> typeRef;
|
public TypeKey(
|
||||||
|
final CallType callType,
|
||||||
public TypeKey(
|
final EntityType entityType,
|
||||||
final CallType callType,
|
final TypeReference<T> typeRef) {
|
||||||
final EntityType entityType,
|
|
||||||
final TypeReference<T> typeRef) {
|
this.callType = callType;
|
||||||
|
this.entityType = entityType;
|
||||||
this.callType = callType;
|
this.typeRef = typeRef;
|
||||||
this.entityType = entityType;
|
}
|
||||||
this.typeRef = typeRef;
|
|
||||||
}
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
@Override
|
final int prime = 31;
|
||||||
public int hashCode() {
|
int result = 1;
|
||||||
final int prime = 31;
|
result = prime * result + ((this.callType == null) ? 0 : this.callType.hashCode());
|
||||||
int result = 1;
|
result = prime * result + ((this.entityType == null) ? 0 : this.entityType.hashCode());
|
||||||
result = prime * result + ((this.callType == null) ? 0 : this.callType.hashCode());
|
return result;
|
||||||
result = prime * result + ((this.entityType == null) ? 0 : this.entityType.hashCode());
|
}
|
||||||
return result;
|
|
||||||
}
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
@Override
|
if (this == obj)
|
||||||
public boolean equals(final Object obj) {
|
return true;
|
||||||
if (this == obj)
|
if (obj == null)
|
||||||
return true;
|
return false;
|
||||||
if (obj == null)
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
final TypeKey<?> other = (TypeKey<?>) obj;
|
||||||
return false;
|
if (this.callType != other.callType)
|
||||||
final TypeKey<?> other = (TypeKey<?>) obj;
|
return false;
|
||||||
if (this.callType != other.callType)
|
if (this.entityType != other.entityType)
|
||||||
return false;
|
return false;
|
||||||
if (this.entityType != other.entityType)
|
return true;
|
||||||
return false;
|
}
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,61 +1,59 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
|
||||||
public class RestCallError extends RuntimeException implements APIMessageError {
|
public class RestCallError extends RuntimeException implements APIMessageError {
|
||||||
|
|
||||||
private static final long serialVersionUID = -5201349295667957490L;
|
private static final long serialVersionUID = -5201349295667957490L;
|
||||||
|
|
||||||
final List<APIMessage> errors;
|
final List<APIMessage> errors;
|
||||||
|
|
||||||
public RestCallError(final String message, final Throwable cause) {
|
public RestCallError(final String message, final Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
this.errors = new ArrayList<>();
|
this.errors = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestCallError(final String message, final Collection<APIMessage> apiErrors) {
|
public RestCallError(final String message, final Collection<APIMessage> apiErrors) {
|
||||||
super(message);
|
super(message);
|
||||||
this.errors = Utils.immutableListOf(apiErrors);
|
this.errors = Utils.immutableListOf(apiErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestCallError(final String message) {
|
public RestCallError(final String message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.errors = new ArrayList<>();
|
this.errors = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<APIMessage> getErrorMessages() {
|
public List<APIMessage> getErrorMessages() {
|
||||||
return this.errors;
|
return this.errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasErrorMessages() {
|
public boolean hasErrorMessages() {
|
||||||
return !this.errors.isEmpty();
|
return !this.errors.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFieldValidationError() {
|
public boolean isFieldValidationError() {
|
||||||
return this.errors
|
return this.errors
|
||||||
.stream()
|
.stream()
|
||||||
.filter(error -> APIMessage.ErrorMessage.FIELD_VALIDATION.isOf(error))
|
.anyMatch(APIMessage.ErrorMessage.FIELD_VALIDATION::isOf);
|
||||||
.findFirst()
|
}
|
||||||
.isPresent();
|
|
||||||
}
|
@Override
|
||||||
|
public String toString() {
|
||||||
@Override
|
return "RestCallError [errors=" + this.errors + "]";
|
||||||
public String toString() {
|
}
|
||||||
return "RestCallError [errors=" + this.errors + "]";
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,74 +1,74 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
||||||
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType;
|
||||||
|
|
||||||
/** Interface to SEB Server webservice API thought RestCall's
|
/** Interface to SEB Server webservice API thought RestCall's
|
||||||
* or thought Spring's RestTemplate on lower level.
|
* or thought Spring's RestTemplate on lower level.
|
||||||
*
|
*
|
||||||
* A RestCall's can be used to call a specified SEB Server webservice API endpoint with given request parameter.
|
* A RestCall's can be used to call a specified SEB Server webservice API endpoint with given request parameter.
|
||||||
* This service collects all the available RestCalls and map them by Class type or EntityType and CallType.
|
* This service collects all the available RestCalls and map them by Class type or EntityType and CallType.
|
||||||
*
|
*
|
||||||
* For Example if one want to get a certain User-Account by API request on SEB Server webservice API:
|
* For Example if one want to get a certain User-Account by API request on SEB Server webservice API:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* UserInfo userInfo = RestService.getBuilder(GetUserAccount.class)
|
* UserInfo userInfo = RestService.getBuilder(GetUserAccount.class)
|
||||||
* .withURIVariable(API.PARAM_MODEL_ID, user-account-id) adds an URI path variable
|
* .withURIVariable(API.PARAM_MODEL_ID, user-account-id) adds an URI path variable
|
||||||
* .withQueryParam(API.PARAM_INSTITUTION_ID, institutionId) adds a URI query parameter
|
* .withQueryParam(API.PARAM_INSTITUTION_ID, institutionId) adds a URI query parameter
|
||||||
* .call() executes the API request call
|
* .call() executes the API request call
|
||||||
* .get(pageContext::notifyError) gets the result or notify an error to the user if happened
|
* .get(pageContext::notifyError) gets the result or notify an error to the user if happened
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public interface RestService {
|
public interface RestService {
|
||||||
|
|
||||||
/** Get Spring's RestTemplate that is used within this service.
|
/** Get Spring's RestTemplate that is used within this service.
|
||||||
*
|
*
|
||||||
* @return Spring's RestTemplate that is used within this service. */
|
* @return Spring's RestTemplate that is used within this service. */
|
||||||
RestTemplate getWebserviceAPIRestTemplate();
|
RestTemplate getWebserviceAPIRestTemplate();
|
||||||
|
|
||||||
/** Get Spring's UriComponentsBuilder that is used within this service.
|
/** Get Spring's UriComponentsBuilder that is used within this service.
|
||||||
*
|
*
|
||||||
* @return Spring's UriComponentsBuilder that is used within this service. */
|
* @return Spring's UriComponentsBuilder that is used within this service. */
|
||||||
UriComponentsBuilder getWebserviceURIBuilder();
|
UriComponentsBuilder getWebserviceURIBuilder();
|
||||||
|
|
||||||
/** Get a certain RestCall by Class type.
|
/** Get a certain RestCall by Class type.
|
||||||
*
|
*
|
||||||
* @param type the Class type of the RestCall
|
* @param type the Class type of the RestCall
|
||||||
* @return RestCall instance */
|
* @return RestCall instance */
|
||||||
<T> RestCall<T> getRestCall(Class<? extends RestCall<T>> type);
|
<T> RestCall<T> getRestCall(Class<? extends RestCall<T>> type);
|
||||||
|
|
||||||
/** Get a certain RestCall by EntityType and CallType.
|
/** Get a certain RestCall by EntityType and CallType.
|
||||||
* NOTE not all RestCall can be get within this method. Only the ones that have a defined CallType
|
* NOTE not all RestCall can be get within this method. Only the ones that have a defined CallType
|
||||||
*
|
*
|
||||||
* @param entityType The EntityType of the RestCall
|
* @param entityType The EntityType of the RestCall
|
||||||
* @param callType The CallType of the RestCall (not UNDEFINDED)
|
* @param callType The CallType of the RestCall (not UNDEFINED)
|
||||||
* @return RestCall instance */
|
* @return RestCall instance */
|
||||||
<T> RestCall<T> getRestCall(EntityType entityType, CallType callType);
|
<T> RestCall<T> getRestCall(EntityType entityType, CallType callType);
|
||||||
|
|
||||||
/** Get a certain RestCallBuilder by RestCall Class type.
|
/** Get a certain RestCallBuilder by RestCall Class type.
|
||||||
*
|
*
|
||||||
* @param type the Class type of the RestCall
|
* @param type the Class type of the RestCall
|
||||||
* @return RestCallBuilder instance to build a dedicated call and execute it */
|
* @return RestCallBuilder instance to build a dedicated call and execute it */
|
||||||
<T> RestCall<T>.RestCallBuilder getBuilder(Class<? extends RestCall<T>> type);
|
<T> RestCall<T>.RestCallBuilder getBuilder(Class<? extends RestCall<T>> type);
|
||||||
|
|
||||||
/** Get a certain RestCallBuilder by EntityType and CallType.
|
/** Get a certain RestCallBuilder by EntityType and CallType.
|
||||||
*
|
*
|
||||||
* @param entityType The EntityType of the RestCall to get a builder for
|
* @param entityType The EntityType of the RestCall to get a builder for
|
||||||
* @param callType The CallType of the RestCall to get a builder for (not UNDEFINDED)
|
* @param callType The CallType of the RestCall to get a builder for (not UNDEFINED)
|
||||||
* @return RestCallBuilder instance to build a dedicated call and execute it */
|
* @return RestCallBuilder instance to build a dedicated call and execute it */
|
||||||
<T> RestCall<T>.RestCallBuilder getBuilder(
|
<T> RestCall<T>.RestCallBuilder getBuilder(
|
||||||
EntityType entityType,
|
EntityType entityType,
|
||||||
CallType callType);
|
CallType callType);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,40 +1,41 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||||
|
|
||||||
@Lazy
|
|
||||||
@Component
|
@Lazy
|
||||||
@GuiProfile
|
@Component
|
||||||
public class SaveUserAccount extends RestCall<UserInfo> {
|
@GuiProfile
|
||||||
|
public class SaveUserAccount extends RestCall<UserInfo> {
|
||||||
public SaveUserAccount() {
|
|
||||||
super(new TypeKey<>(
|
public SaveUserAccount() {
|
||||||
CallType.SAVE,
|
super(new TypeKey<>(
|
||||||
EntityType.USER,
|
CallType.SAVE,
|
||||||
new TypeReference<UserInfo>() {
|
EntityType.USER,
|
||||||
}),
|
new TypeReference<UserInfo>() {
|
||||||
HttpMethod.PUT,
|
}),
|
||||||
MediaType.APPLICATION_JSON_UTF8,
|
HttpMethod.PUT,
|
||||||
API.USER_ACCOUNT_ENDPOINT);
|
MediaType.APPLICATION_JSON_UTF8,
|
||||||
}
|
API.USER_ACCOUNT_ENDPOINT);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,348 +1,344 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.annotation.ScopedProxyMode;
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege.RoleTypeKey;
|
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege.RoleTypeKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
|
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
public class CurrentUser {
|
public class CurrentUser {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(CurrentUser.class);
|
private static final Logger log = LoggerFactory.getLogger(CurrentUser.class);
|
||||||
|
|
||||||
private final AuthorizationContextHolder authorizationContextHolder;
|
private final AuthorizationContextHolder authorizationContextHolder;
|
||||||
private SEBServerAuthorizationContext authContext = null;
|
private SEBServerAuthorizationContext authContext = null;
|
||||||
private Map<RoleTypeKey, Privilege> privileges = null;
|
private Map<RoleTypeKey, Privilege> privileges = null;
|
||||||
private final Map<String, String> attributes;
|
private final Map<String, String> attributes;
|
||||||
|
|
||||||
public CurrentUser(final AuthorizationContextHolder authorizationContextHolder) {
|
public CurrentUser(final AuthorizationContextHolder authorizationContextHolder) {
|
||||||
this.authorizationContextHolder = authorizationContextHolder;
|
this.authorizationContextHolder = authorizationContextHolder;
|
||||||
this.attributes = new HashMap<>();
|
this.attributes = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void putAttribute(final String name, final String value) {
|
public void putAttribute(final String name, final String value) {
|
||||||
this.attributes.put(name, value);
|
this.attributes.put(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAttribute(final String name) {
|
public String getAttribute(final String name) {
|
||||||
return this.attributes.get(name);
|
return this.attributes.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthorizationContextHolder getAuthorizationContextHolder() {
|
public AuthorizationContextHolder getAuthorizationContextHolder() {
|
||||||
return this.authorizationContextHolder;
|
return this.authorizationContextHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserInfo get() {
|
public UserInfo get() {
|
||||||
|
|
||||||
if (isAvailable()) {
|
if (isAvailable()) {
|
||||||
return this.authContext
|
return this.authContext
|
||||||
.getLoggedInUser()
|
.getLoggedInUser()
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleIllegalSessionState();
|
return handleIllegalSessionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserInfo getOrHandleError(final Function<Exception, UserInfo> errorHandler) {
|
public UserInfo getOrHandleError(final Function<Exception, UserInfo> errorHandler) {
|
||||||
if (isAvailable()) {
|
if (isAvailable()) {
|
||||||
return this.authContext
|
return this.authContext
|
||||||
.getLoggedInUser()
|
.getLoggedInUser()
|
||||||
.get(errorHandler);
|
.get(errorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleIllegalSessionState();
|
return handleIllegalSessionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserInfo handleIllegalSessionState() {
|
private UserInfo handleIllegalSessionState() {
|
||||||
log.warn("Current user requested but no user is currently logged in");
|
log.warn("Current user requested but no user is currently logged in");
|
||||||
this.logout();
|
this.logout();
|
||||||
throw new IllegalUserSessionStateException("User not logged in");
|
throw new IllegalUserSessionStateException("User not logged in");
|
||||||
}
|
}
|
||||||
|
|
||||||
public GrantCheck grantCheck(final EntityType entityType) {
|
public GrantCheck grantCheck(final EntityType entityType) {
|
||||||
return new GrantCheck(entityType);
|
return new GrantCheck(entityType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityGrantCheck entityGrantCheck(final GrantEntity grantEntity) {
|
public EntityGrantCheck entityGrantCheck(final GrantEntity grantEntity) {
|
||||||
return new EntityGrantCheck(grantEntity);
|
return new EntityGrantCheck(grantEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBasePrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
public boolean hasBasePrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
||||||
return hasPrivilege(privilegeType, entityType, null, null);
|
return hasPrivilege(privilegeType, entityType, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasInstitutionalPrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
public boolean hasInstitutionalPrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
||||||
final UserInfo userInfo = get();
|
final UserInfo userInfo = get();
|
||||||
return hasPrivilege(privilegeType, entityType, userInfo.institutionId, null);
|
return hasPrivilege(privilegeType, entityType, userInfo.institutionId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPrivilege(
|
public boolean hasPrivilege(
|
||||||
final PrivilegeType privilegeType,
|
final PrivilegeType privilegeType,
|
||||||
final EntityType entityType,
|
final EntityType entityType,
|
||||||
final Long institutionId,
|
final Long institutionId,
|
||||||
final String ownerId) {
|
final String ownerId) {
|
||||||
if (loadPrivileges()) {
|
if (loadPrivileges()) {
|
||||||
try {
|
try {
|
||||||
final UserInfo userInfo = get();
|
final UserInfo userInfo = get();
|
||||||
return userInfo
|
return userInfo
|
||||||
.getRoles()
|
.getRoles()
|
||||||
.stream()
|
.stream()
|
||||||
.map(roleName -> UserRole.valueOf(roleName))
|
.map(UserRole::valueOf)
|
||||||
.map(role -> new RoleTypeKey(entityType, role))
|
.map(role -> new RoleTypeKey(entityType, role))
|
||||||
.map(key -> this.privileges.get(key))
|
.map(key -> this.privileges.get(key))
|
||||||
.filter(priv -> (priv != null) && priv.hasGrant(
|
.anyMatch(privilege -> (privilege != null) && privilege.hasGrant(
|
||||||
userInfo.uuid,
|
userInfo.uuid,
|
||||||
userInfo.institutionId,
|
userInfo.institutionId,
|
||||||
privilegeType,
|
privilegeType,
|
||||||
institutionId,
|
institutionId,
|
||||||
ownerId))
|
ownerId));
|
||||||
.findFirst()
|
} catch (final Exception e) {
|
||||||
.isPresent();
|
log.error("Failed to verify privilege: PrivilegeType {} EntityType {}",
|
||||||
} catch (final Exception e) {
|
privilegeType, entityType, e);
|
||||||
log.error("Failed to verify privilege: PrivilegeType {} EntityType {}",
|
}
|
||||||
privilegeType, entityType, e);
|
}
|
||||||
}
|
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
return false;
|
|
||||||
}
|
public boolean hasPrivilege(
|
||||||
|
final PrivilegeType privilegeType,
|
||||||
public boolean hasPrivilege(
|
final GrantEntity grantEntity) {
|
||||||
final PrivilegeType privilegeType,
|
|
||||||
final GrantEntity grantEntity) {
|
if (loadPrivileges()) {
|
||||||
|
final EntityType entityType = grantEntity.entityType();
|
||||||
if (loadPrivileges()) {
|
try {
|
||||||
final EntityType entityType = grantEntity.entityType();
|
final UserInfo userInfo = get();
|
||||||
try {
|
return userInfo.getRoles()
|
||||||
final UserInfo userInfo = get();
|
.stream()
|
||||||
return userInfo.getRoles()
|
.map(UserRole::valueOf)
|
||||||
.stream()
|
.map(role -> new RoleTypeKey(entityType, role))
|
||||||
.map(roleName -> UserRole.valueOf(roleName))
|
.map(key -> this.privileges.get(key))
|
||||||
.map(role -> new RoleTypeKey(entityType, role))
|
.anyMatch(privilege -> (privilege != null) && privilege.hasGrant(
|
||||||
.map(key -> this.privileges.get(key))
|
userInfo.uuid,
|
||||||
.filter(priv -> (priv != null) && priv.hasGrant(
|
userInfo.institutionId,
|
||||||
userInfo.uuid,
|
privilegeType,
|
||||||
userInfo.institutionId,
|
grantEntity.getInstitutionId(),
|
||||||
privilegeType,
|
grantEntity.getOwnerId()));
|
||||||
grantEntity.getInstitutionId(),
|
} catch (final Exception e) {
|
||||||
grantEntity.getOwnerId()))
|
log.error("Failed to verify privilege: PrivilegeType {} EntityType {}",
|
||||||
.findFirst()
|
privilegeType, entityType, e);
|
||||||
.isPresent();
|
}
|
||||||
} catch (final Exception e) {
|
}
|
||||||
log.error("Failed to verify privilege: PrivilegeType {} EntityType {}",
|
|
||||||
privilegeType, entityType, e);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public boolean isAvailable() {
|
||||||
return false;
|
updateContext();
|
||||||
}
|
return this.authContext != null && this.authContext.isLoggedIn();
|
||||||
|
}
|
||||||
public boolean isAvailable() {
|
|
||||||
updateContext();
|
public void refresh(final UserInfo userInfo) {
|
||||||
return this.authContext != null && this.authContext.isLoggedIn();
|
this.authContext.refreshUser(userInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh(final UserInfo userInfo) {
|
public boolean logout() {
|
||||||
this.authContext.refreshUser(userInfo);
|
if (this.attributes != null) {
|
||||||
}
|
this.attributes.clear();
|
||||||
|
}
|
||||||
public boolean logout() {
|
|
||||||
if (this.attributes != null) {
|
this.privileges = null;
|
||||||
this.attributes.clear();
|
|
||||||
}
|
if (isAvailable()) {
|
||||||
|
if (this.authContext.logout()) {
|
||||||
this.privileges = null;
|
this.authContext = null;
|
||||||
|
return true;
|
||||||
if (isAvailable()) {
|
} else {
|
||||||
if (this.authContext.logout()) {
|
return false;
|
||||||
this.authContext = null;
|
}
|
||||||
return true;
|
} else {
|
||||||
} else {
|
try {
|
||||||
return false;
|
return this.authorizationContextHolder
|
||||||
}
|
.getAuthorizationContext()
|
||||||
} else {
|
.logout();
|
||||||
try {
|
} catch (final Exception e) {
|
||||||
return this.authorizationContextHolder
|
log.warn("Unexpected error while logout: {}", e.getMessage());
|
||||||
.getAuthorizationContext()
|
return false;
|
||||||
.logout();
|
}
|
||||||
} catch (final Exception e) {
|
}
|
||||||
log.warn("Unexpected error while logout: {}", e.getMessage());
|
}
|
||||||
return false;
|
|
||||||
}
|
private void updateContext() {
|
||||||
}
|
if (this.authContext == null || !this.authContext.isValid()) {
|
||||||
}
|
this.authContext = this.authorizationContextHolder.getAuthorizationContext();
|
||||||
|
}
|
||||||
private void updateContext() {
|
}
|
||||||
if (this.authContext == null || !this.authContext.isValid()) {
|
|
||||||
this.authContext = this.authorizationContextHolder.getAuthorizationContext();
|
private boolean loadPrivileges() {
|
||||||
}
|
if (this.privileges != null) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
private boolean loadPrivileges() {
|
|
||||||
if (this.privileges != null) {
|
updateContext();
|
||||||
return true;
|
if (this.authContext != null) {
|
||||||
}
|
try {
|
||||||
|
final WebserviceURIService webserviceURIService =
|
||||||
updateContext();
|
this.authorizationContextHolder.getWebserviceURIService();
|
||||||
if (this.authContext != null) {
|
final ResponseEntity<Collection<Privilege>> exchange = this.authContext.getRestTemplate()
|
||||||
try {
|
.exchange(
|
||||||
final WebserviceURIService webserviceURIService =
|
webserviceURIService.getURIBuilder()
|
||||||
this.authorizationContextHolder.getWebserviceURIService();
|
.path(API.PRIVILEGES_ENDPOINT)
|
||||||
final ResponseEntity<Collection<Privilege>> exchange = this.authContext.getRestTemplate()
|
.toUriString(),
|
||||||
.exchange(
|
HttpMethod.GET,
|
||||||
webserviceURIService.getURIBuilder()
|
HttpEntity.EMPTY,
|
||||||
.path(API.PRIVILEGES_ENDPOINT)
|
Constants.TYPE_REFERENCE_PRIVILEGES);
|
||||||
.toUriString(),
|
|
||||||
HttpMethod.GET,
|
if (exchange.getStatusCodeValue() == HttpStatus.OK.value()) {
|
||||||
HttpEntity.EMPTY,
|
final Collection<Privilege> privileges = exchange.getBody();
|
||||||
Constants.TYPE_REFERENCE_PRIVILEGES);
|
if (privileges != null) {
|
||||||
|
this.privileges = privileges
|
||||||
if (exchange.getStatusCodeValue() == HttpStatus.OK.value()) {
|
.stream()
|
||||||
final Collection<Privilege> privileges = exchange.getBody();
|
.reduce(new HashMap<>(),
|
||||||
if (privileges != null) {
|
(map, privilege) -> {
|
||||||
this.privileges = privileges
|
map.put(privilege.roleTypeKey, privilege);
|
||||||
.stream()
|
return map;
|
||||||
.reduce(new HashMap<RoleTypeKey, Privilege>(),
|
},
|
||||||
(map, priv) -> {
|
(map1, map2) -> {
|
||||||
map.put(priv.roleTypeKey, priv);
|
map1.putAll(map2);
|
||||||
return map;
|
return map1;
|
||||||
},
|
});
|
||||||
(map1, map2) -> {
|
} else {
|
||||||
map1.putAll(map2);
|
log.error("Failed to get Privileges from webservice API: {}", exchange);
|
||||||
return map1;
|
return false;
|
||||||
});
|
}
|
||||||
} else {
|
|
||||||
log.error("Failed to get Privileges from webservice API: {}", exchange);
|
return true;
|
||||||
return false;
|
} else {
|
||||||
}
|
log.error("Failed to get Privileges from webservice API: {}", exchange);
|
||||||
|
return false;
|
||||||
return true;
|
}
|
||||||
} else {
|
|
||||||
log.error("Failed to get Privileges from webservice API: {}", exchange);
|
} catch (final Exception e) {
|
||||||
return false;
|
log.error("Failed to get Privileges from webservice API: ", e);
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
} catch (final Exception e) {
|
} else {
|
||||||
log.error("Failed to get Privileges from webservice API: ", e);
|
log.error("Failed to get Privileges from webservice API. No AuthorizationContext available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
log.error("Failed to get Privileges from webservice API. No AuthorizationContext available");
|
|
||||||
return false;
|
/** Wrapper can be used for base and institutional grant checks for a specified EntityType */
|
||||||
}
|
public class GrantCheck {
|
||||||
}
|
private final EntityType entityType;
|
||||||
|
|
||||||
/** Wrapper can be used for base and institutional grant checks for a specified EntityType */
|
protected GrantCheck(final EntityType entityType) {
|
||||||
public class GrantCheck {
|
this.entityType = entityType;
|
||||||
private final EntityType entityType;
|
}
|
||||||
|
|
||||||
protected GrantCheck(final EntityType entityType) {
|
/** Checks the base read-only privilege grant
|
||||||
this.entityType = entityType;
|
*
|
||||||
}
|
* @return true on read-only privilege grant on wrapped EntityType */
|
||||||
|
public boolean r() {
|
||||||
/** Checks the base read-only privilege grant
|
return hasBasePrivilege(PrivilegeType.READ, this.entityType);
|
||||||
*
|
}
|
||||||
* @return true on read-only privilege grant on wrapped EntityType */
|
|
||||||
public boolean r() {
|
/** Checks the base modify privilege grant
|
||||||
return hasBasePrivilege(PrivilegeType.READ, this.entityType);
|
*
|
||||||
}
|
* @return true on modify privilege grant on wrapped EntityType */
|
||||||
|
public boolean m() {
|
||||||
/** Checks the base modify privilege grant
|
return hasBasePrivilege(PrivilegeType.MODIFY, this.entityType);
|
||||||
*
|
}
|
||||||
* @return true on modify privilege grant on wrapped EntityType */
|
|
||||||
public boolean m() {
|
/** Checks the base write privilege grant
|
||||||
return hasBasePrivilege(PrivilegeType.MODIFY, this.entityType);
|
*
|
||||||
}
|
* @return true on write privilege grant on wrapped EntityType */
|
||||||
|
public boolean w() {
|
||||||
/** Checks the base write privilege grant
|
return hasBasePrivilege(PrivilegeType.WRITE, this.entityType);
|
||||||
*
|
}
|
||||||
* @return true on write privilege grant on wrapped EntityType */
|
|
||||||
public boolean w() {
|
/** Checks the institutional read-only privilege grant
|
||||||
return hasBasePrivilege(PrivilegeType.WRITE, this.entityType);
|
*
|
||||||
}
|
* @return true institutional read-only privilege grant on wrapped EntityType */
|
||||||
|
public boolean ir() {
|
||||||
/** Checks the institutional read-only privilege grant
|
return hasInstitutionalPrivilege(PrivilegeType.READ, this.entityType);
|
||||||
*
|
}
|
||||||
* @return true institutional read-only privilege grant on wrapped EntityType */
|
|
||||||
public boolean ir() {
|
/** Checks the institutional modify privilege grant
|
||||||
return hasInstitutionalPrivilege(PrivilegeType.READ, this.entityType);
|
*
|
||||||
}
|
* @return true institutional modify privilege grant on wrapped EntityType */
|
||||||
|
public boolean im() {
|
||||||
/** Checks the institutional modify privilege grant
|
return hasInstitutionalPrivilege(PrivilegeType.MODIFY, this.entityType);
|
||||||
*
|
}
|
||||||
* @return true institutional modify privilege grant on wrapped EntityType */
|
|
||||||
public boolean im() {
|
/** Checks the institutional write privilege grant
|
||||||
return hasInstitutionalPrivilege(PrivilegeType.MODIFY, this.entityType);
|
*
|
||||||
}
|
* @return true institutional write privilege grant on wrapped EntityType */
|
||||||
|
public boolean iw() {
|
||||||
/** Checks the institutional write privilege grant
|
return hasInstitutionalPrivilege(PrivilegeType.WRITE, this.entityType);
|
||||||
*
|
}
|
||||||
* @return true institutional write privilege grant on wrapped EntityType */
|
}
|
||||||
public boolean iw() {
|
|
||||||
return hasInstitutionalPrivilege(PrivilegeType.WRITE, this.entityType);
|
/** Wrapper can be used for Entity based grant checks */
|
||||||
}
|
public class EntityGrantCheck {
|
||||||
}
|
private final GrantEntity grantEntity;
|
||||||
|
|
||||||
/** Wrapper can be used for Entity based grant checks */
|
protected EntityGrantCheck(final GrantEntity grantEntity) {
|
||||||
public class EntityGrantCheck {
|
this.grantEntity = grantEntity;
|
||||||
private final GrantEntity grantEntity;
|
}
|
||||||
|
|
||||||
protected EntityGrantCheck(final GrantEntity grantEntity) {
|
/** Checks the read-only privilege grant for wrapped grantEntity
|
||||||
this.grantEntity = grantEntity;
|
*
|
||||||
}
|
* @return true on read-only privilege grant for wrapped grantEntity */
|
||||||
|
public boolean r() {
|
||||||
/** Checks the read-only privilege grant for wrapped grantEntity
|
return hasPrivilege(PrivilegeType.READ, this.grantEntity);
|
||||||
*
|
}
|
||||||
* @return true on read-only privilege grant for wrapped grantEntity */
|
|
||||||
public boolean r() {
|
/** Checks the modify privilege grant for wrapped grantEntity
|
||||||
return hasPrivilege(PrivilegeType.READ, this.grantEntity);
|
*
|
||||||
}
|
* @return true on modify privilege grant for wrapped grantEntity */
|
||||||
|
public boolean m() {
|
||||||
/** Checks the modify privilege grant for wrapped grantEntity
|
return hasPrivilege(PrivilegeType.MODIFY, this.grantEntity);
|
||||||
*
|
}
|
||||||
* @return true on modify privilege grant for wrapped grantEntity */
|
|
||||||
public boolean m() {
|
/** Checks the write privilege grant for wrapped grantEntity
|
||||||
return hasPrivilege(PrivilegeType.MODIFY, this.grantEntity);
|
*
|
||||||
}
|
* @return true on write privilege grant for wrapped grantEntity */
|
||||||
|
public boolean w() {
|
||||||
/** Checks the write privilege grant for wrapped grantEntity
|
return hasPrivilege(PrivilegeType.WRITE, this.grantEntity);
|
||||||
*
|
}
|
||||||
* @return true on write privilege grant for wrapped grantEntity */
|
}
|
||||||
public boolean w() {
|
|
||||||
return hasPrivilege(PrivilegeType.WRITE, this.grantEntity);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,333 +1,331 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
||||||
|
|
||||||
import java.io.IOException;
|
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
||||||
import java.net.URI;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import java.nio.charset.Charset;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
import java.util.Arrays;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import java.util.Collections;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import java.util.List;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import javax.servlet.http.HttpSession;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.slf4j.Logger;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
|
||||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
||||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
|
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
|
||||||
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
|
||||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
|
import org.springframework.web.client.RequestCallback;
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.web.client.ResponseExtractor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.web.client.RestClientException;
|
||||||
import org.springframework.web.client.RequestCallback;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.client.ResponseExtractor;
|
|
||||||
import org.springframework.web.client.RestClientException;
|
import javax.servlet.http.HttpSession;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
import java.nio.charset.StandardCharsets;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
import java.util.Arrays;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import java.util.Collections;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import java.util.List;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
@Lazy
|
||||||
|
@Component
|
||||||
@Lazy
|
@GuiProfile
|
||||||
@Component
|
public class OAuth2AuthorizationContextHolder implements AuthorizationContextHolder {
|
||||||
@GuiProfile
|
|
||||||
public class OAuth2AuthorizationContextHolder implements AuthorizationContextHolder {
|
private static final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationContextHolder.class);
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationContextHolder.class);
|
private static final String CONTEXT_HOLDER_ATTRIBUTE = "CONTEXT_HOLDER_ATTRIBUTE";
|
||||||
|
|
||||||
private static final String CONTEXT_HOLDER_ATTRIBUTE = "CONTEXT_HOLDER_ATTRIBUTE";
|
private final String guiClientId;
|
||||||
|
private final String guiClientSecret;
|
||||||
private final String guiClientId;
|
private final WebserviceURIService webserviceURIService;
|
||||||
private final String guiClientSecret;
|
private final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
|
||||||
private final WebserviceURIService webserviceURIService;
|
|
||||||
private final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
|
@Autowired
|
||||||
|
public OAuth2AuthorizationContextHolder(
|
||||||
@Autowired
|
@Value("${sebserver.webservice.api.admin.clientId}") final String guiClientId,
|
||||||
public OAuth2AuthorizationContextHolder(
|
@Value("${sebserver.webservice.api.admin.clientSecret}") final String guiClientSecret,
|
||||||
@Value("${sebserver.webservice.api.admin.clientId}") final String guiClientId,
|
final WebserviceURIService webserviceURIService,
|
||||||
@Value("${sebserver.webservice.api.admin.clientSecret}") final String guiClientSecret,
|
final ClientHttpRequestFactoryService clientHttpRequestFactoryService) {
|
||||||
final WebserviceURIService webserviceURIService,
|
|
||||||
final ClientHttpRequestFactoryService clientHttpRequestFactoryService) {
|
this.guiClientId = guiClientId;
|
||||||
|
this.guiClientSecret = guiClientSecret;
|
||||||
this.guiClientId = guiClientId;
|
this.webserviceURIService = webserviceURIService;
|
||||||
this.guiClientSecret = guiClientSecret;
|
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
|
||||||
this.webserviceURIService = webserviceURIService;
|
}
|
||||||
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
|
|
||||||
}
|
@Override
|
||||||
|
public WebserviceURIService getWebserviceURIService() {
|
||||||
@Override
|
return this.webserviceURIService;
|
||||||
public WebserviceURIService getWebserviceURIService() {
|
}
|
||||||
return this.webserviceURIService;
|
|
||||||
}
|
@Override
|
||||||
|
public SEBServerAuthorizationContext getAuthorizationContext(final HttpSession session) {
|
||||||
@Override
|
log.debug("Trying to get OAuth2AuthorizationContext from HttpSession: {}", session.getId());
|
||||||
public SEBServerAuthorizationContext getAuthorizationContext(final HttpSession session) {
|
|
||||||
log.debug("Trying to get OAuth2AuthorizationContext from HttpSession: {}", session.getId());
|
OAuth2AuthorizationContext context =
|
||||||
|
(OAuth2AuthorizationContext) session.getAttribute(CONTEXT_HOLDER_ATTRIBUTE);
|
||||||
OAuth2AuthorizationContext context =
|
|
||||||
(OAuth2AuthorizationContext) session.getAttribute(CONTEXT_HOLDER_ATTRIBUTE);
|
if (context == null || !context.valid) {
|
||||||
|
log.debug(
|
||||||
if (context == null || !context.valid) {
|
"OAuth2AuthorizationContext for HttpSession: {} is not present or is invalid. "
|
||||||
log.debug(
|
+ "Create new OAuth2AuthorizationContext for this session",
|
||||||
"OAuth2AuthorizationContext for HttpSession: {} is not present or is invalid. "
|
session.getId());
|
||||||
+ "Create new OAuth2AuthorizationContext for this session",
|
|
||||||
session.getId());
|
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
|
||||||
|
.getClientHttpRequestFactory()
|
||||||
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
|
.getOrThrow();
|
||||||
.getClientHttpRequestFactory()
|
|
||||||
.getOrThrow();
|
context = new OAuth2AuthorizationContext(
|
||||||
|
this.guiClientId,
|
||||||
context = new OAuth2AuthorizationContext(
|
this.guiClientSecret,
|
||||||
this.guiClientId,
|
this.webserviceURIService,
|
||||||
this.guiClientSecret,
|
clientHttpRequestFactory);
|
||||||
this.webserviceURIService,
|
|
||||||
clientHttpRequestFactory);
|
session.setAttribute(CONTEXT_HOLDER_ATTRIBUTE, context);
|
||||||
|
}
|
||||||
session.setAttribute(CONTEXT_HOLDER_ATTRIBUTE, context);
|
|
||||||
}
|
return context;
|
||||||
|
}
|
||||||
return context;
|
|
||||||
}
|
private static final class DisposableOAuth2RestTemplate extends OAuth2RestTemplate {
|
||||||
|
|
||||||
private static final class DisposableOAuth2RestTemplate extends OAuth2RestTemplate {
|
private boolean enabled = true;
|
||||||
|
|
||||||
private boolean enabled = true;
|
public DisposableOAuth2RestTemplate(final OAuth2ProtectedResourceDetails resource) {
|
||||||
|
super(
|
||||||
public DisposableOAuth2RestTemplate(final OAuth2ProtectedResourceDetails resource) {
|
resource,
|
||||||
super(
|
new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
|
||||||
resource,
|
}
|
||||||
new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
|
|
||||||
}
|
@Override
|
||||||
|
protected <T> T doExecute(
|
||||||
@Override
|
final URI url,
|
||||||
protected <T> T doExecute(
|
final HttpMethod method,
|
||||||
final URI url,
|
final RequestCallback requestCallback,
|
||||||
final HttpMethod method,
|
final ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||||
final RequestCallback requestCallback,
|
|
||||||
final ResponseExtractor<T> responseExtractor) throws RestClientException {
|
if (this.enabled) {
|
||||||
|
return super.doExecute(url, method, requestCallback, responseExtractor);
|
||||||
if (this.enabled) {
|
} else {
|
||||||
return super.doExecute(url, method, requestCallback, responseExtractor);
|
throw new IllegalStateException(
|
||||||
} else {
|
"Error: Forbidden execution call on disabled DisposableOAuth2RestTemplate");
|
||||||
throw new IllegalStateException(
|
}
|
||||||
"Error: Forbidden execution call on disabled DisposableOAuth2RestTemplate");
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
private static final class OAuth2AuthorizationContext implements SEBServerAuthorizationContext {
|
||||||
|
|
||||||
private static final class OAuth2AuthorizationContext implements SEBServerAuthorizationContext {
|
private static final String GRANT_TYPE = "password";
|
||||||
|
private static final List<String> SCOPES = Collections.unmodifiableList(
|
||||||
private static final String GRANT_TYPE = "password";
|
Arrays.asList("read", "write"));
|
||||||
private static final List<String> SCOPES = Collections.unmodifiableList(
|
|
||||||
Arrays.asList("read", "write"));
|
private boolean valid = true;
|
||||||
|
|
||||||
private boolean valid = true;
|
private final ResourceOwnerPasswordResourceDetails resource;
|
||||||
|
private final DisposableOAuth2RestTemplate restTemplate;
|
||||||
private final ResourceOwnerPasswordResourceDetails resource;
|
private final String revokeTokenURI;
|
||||||
private final DisposableOAuth2RestTemplate restTemplate;
|
private final String currentUserURI;
|
||||||
private final String revokeTokenURI;
|
|
||||||
private final String currentUserURI;
|
private Result<UserInfo> loggedInUser = null;
|
||||||
|
|
||||||
private Result<UserInfo> loggedInUser = null;
|
OAuth2AuthorizationContext(
|
||||||
|
final String guiClientId,
|
||||||
OAuth2AuthorizationContext(
|
final String guiClientSecret,
|
||||||
final String guiClientId,
|
final WebserviceURIService webserviceURIService,
|
||||||
final String guiClientSecret,
|
final ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||||
final WebserviceURIService webserviceURIService,
|
|
||||||
final ClientHttpRequestFactory clientHttpRequestFactory) {
|
this.resource = new ResourceOwnerPasswordResourceDetails();
|
||||||
|
this.resource.setAccessTokenUri(webserviceURIService.getOAuthTokenURI());
|
||||||
this.resource = new ResourceOwnerPasswordResourceDetails();
|
this.resource.setClientId(guiClientId);
|
||||||
this.resource.setAccessTokenUri(webserviceURIService.getOAuthTokenURI());
|
this.resource.setClientSecret(guiClientSecret);
|
||||||
this.resource.setClientId(guiClientId);
|
this.resource.setGrantType(GRANT_TYPE);
|
||||||
this.resource.setClientSecret(guiClientSecret);
|
this.resource.setScope(SCOPES);
|
||||||
this.resource.setGrantType(GRANT_TYPE);
|
|
||||||
this.resource.setScope(SCOPES);
|
this.restTemplate = new DisposableOAuth2RestTemplate(this.resource);
|
||||||
|
this.restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||||
this.restTemplate = new DisposableOAuth2RestTemplate(this.resource);
|
this.restTemplate.setErrorHandler(new ErrorHandler(this.resource));
|
||||||
this.restTemplate.setRequestFactory(clientHttpRequestFactory);
|
this.restTemplate
|
||||||
this.restTemplate.setErrorHandler(new ErrorHandler(this.resource));
|
.getMessageConverters()
|
||||||
this.restTemplate
|
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||||
.getMessageConverters()
|
|
||||||
.add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
|
this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI();
|
||||||
|
this.currentUserURI = webserviceURIService.getCurrentUserRequestURI();
|
||||||
this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI();
|
}
|
||||||
this.currentUserURI = webserviceURIService.getCurrentUserRequestURI();
|
|
||||||
}
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
@Override
|
return this.valid;
|
||||||
public boolean isValid() {
|
}
|
||||||
return this.valid;
|
|
||||||
}
|
@Override
|
||||||
|
public boolean isLoggedIn() {
|
||||||
@Override
|
final OAuth2AccessToken accessToken = this.restTemplate.getOAuth2ClientContext().getAccessToken();
|
||||||
public boolean isLoggedIn() {
|
if (accessToken == null || StringUtils.isEmpty(accessToken.toString())) {
|
||||||
final OAuth2AccessToken accessToken = this.restTemplate.getOAuth2ClientContext().getAccessToken();
|
return false;
|
||||||
if (accessToken == null || StringUtils.isEmpty(accessToken.toString())) {
|
}
|
||||||
return false;
|
|
||||||
}
|
try {
|
||||||
|
final ResponseEntity<String> forEntity =
|
||||||
try {
|
this.restTemplate.getForEntity(this.currentUserURI, String.class);
|
||||||
final ResponseEntity<String> forEntity =
|
if (forEntity.getStatusCode() != HttpStatus.OK) {
|
||||||
this.restTemplate.getForEntity(this.currentUserURI, String.class);
|
return false;
|
||||||
if (forEntity.getStatusCode() != HttpStatus.OK) {
|
}
|
||||||
return false;
|
} catch (final Exception e) {
|
||||||
}
|
log.error("Failed to verify logged in user: {}", e.getMessage());
|
||||||
} catch (final Exception e) {
|
return false;
|
||||||
log.error("Failed to verify logged in user: {}", e.getMessage());
|
}
|
||||||
return false;
|
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
return true;
|
|
||||||
}
|
@Override
|
||||||
|
public boolean login(final String username, final CharSequence password) {
|
||||||
@Override
|
if (!this.valid || this.isLoggedIn()) {
|
||||||
public boolean login(final String username, final CharSequence password) {
|
return false;
|
||||||
if (!this.valid || this.isLoggedIn()) {
|
}
|
||||||
return false;
|
|
||||||
}
|
this.resource.setUsername(username);
|
||||||
|
this.resource.setPassword(Utils.toString(password));
|
||||||
this.resource.setUsername(username);
|
|
||||||
this.resource.setPassword(Utils.toString(password));
|
log.debug("Trying to login for user: {}", username);
|
||||||
|
|
||||||
log.debug("Trying to login for user: {}", username);
|
try {
|
||||||
|
this.restTemplate.getAccessToken();
|
||||||
try {
|
log.debug("Got token for user: {}", username);
|
||||||
this.restTemplate.getAccessToken();
|
this.loggedInUser = getLoggedInUser();
|
||||||
log.debug("Got token for user: {}", username);
|
return true;
|
||||||
this.loggedInUser = getLoggedInUser();
|
} catch (final OAuth2AccessDeniedException | AccessDeniedException e) {
|
||||||
return true;
|
log.info("Access Denied for user: {}", username);
|
||||||
} catch (final OAuth2AccessDeniedException | AccessDeniedException e) {
|
return false;
|
||||||
log.info("Access Denied for user: {}", username);
|
}
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
|
public boolean logout() {
|
||||||
@Override
|
// set this context invalid to force creation of a new context on next request
|
||||||
public boolean logout() {
|
this.valid = false;
|
||||||
// set this context invalid to force creation of a new context on next request
|
this.loggedInUser = null;
|
||||||
this.valid = false;
|
if (this.restTemplate.getAccessToken() != null) {
|
||||||
this.loggedInUser = null;
|
// delete the access-token (and refresh-token) on authentication server side
|
||||||
if (this.restTemplate.getAccessToken() != null) {
|
this.restTemplate.delete(this.revokeTokenURI);
|
||||||
// delete the access-token (and refresh-token) on authentication server side
|
// delete the access-token within the RestTemplate
|
||||||
this.restTemplate.delete(this.revokeTokenURI);
|
this.restTemplate.getOAuth2ClientContext().setAccessToken(null);
|
||||||
// delete the access-token within the RestTemplate
|
}
|
||||||
this.restTemplate.getOAuth2ClientContext().setAccessToken(null);
|
// mark the RestTemplate as disposed
|
||||||
}
|
this.restTemplate.enabled = false;
|
||||||
// mark the RestTemplate as disposed
|
return true;
|
||||||
this.restTemplate.enabled = false;
|
}
|
||||||
return true;
|
|
||||||
}
|
@Override
|
||||||
|
public RestTemplate getRestTemplate() {
|
||||||
@Override
|
return this.restTemplate;
|
||||||
public RestTemplate getRestTemplate() {
|
}
|
||||||
return this.restTemplate;
|
|
||||||
}
|
@Override
|
||||||
|
public void refreshUser(final UserInfo userInfo) {
|
||||||
@Override
|
// delete the access-token (and refresh-token) on authentication server side
|
||||||
public void refreshUser(final UserInfo userInfo) {
|
this.restTemplate.delete(this.revokeTokenURI);
|
||||||
// delete the access-token (and refresh-token) on authentication server side
|
// delete the access-token within the RestTemplate
|
||||||
this.restTemplate.delete(this.revokeTokenURI);
|
this.restTemplate.getOAuth2ClientContext().setAccessToken(null);
|
||||||
// delete the access-token within the RestTemplate
|
// check if username has changed
|
||||||
this.restTemplate.getOAuth2ClientContext().setAccessToken(null);
|
if (!userInfo.username.equals(getLoggedInUser().get().username)) {
|
||||||
// check if username has changed
|
// Set new username to be able to request new access token
|
||||||
if (!userInfo.username.equals(getLoggedInUser().get().username)) {
|
this.resource.setUsername(userInfo.username);
|
||||||
// Set new username to be able to request new access token
|
}
|
||||||
this.resource.setUsername(userInfo.username);
|
|
||||||
}
|
// and request new access token
|
||||||
|
this.restTemplate.getAccessToken();
|
||||||
// and request new access token
|
// and reset logged in user by getting actual one from webservice
|
||||||
this.restTemplate.getAccessToken();
|
this.loggedInUser = null;
|
||||||
// and reset logged in user by getting actual one from webservice
|
getLoggedInUser()
|
||||||
this.loggedInUser = null;
|
.getOrThrow();
|
||||||
getLoggedInUser()
|
}
|
||||||
.getOrThrow();
|
|
||||||
}
|
@Override
|
||||||
|
public Result<UserInfo> getLoggedInUser() {
|
||||||
@Override
|
if (this.loggedInUser != null) {
|
||||||
public Result<UserInfo> getLoggedInUser() {
|
return this.loggedInUser;
|
||||||
if (this.loggedInUser != null) {
|
}
|
||||||
return this.loggedInUser;
|
|
||||||
}
|
log.debug("Request logged in User from SEBserver web-service API");
|
||||||
|
|
||||||
log.debug("Request logged in User from SEBserver web-service API");
|
try {
|
||||||
|
if (isValid() && isLoggedIn()) {
|
||||||
try {
|
final ResponseEntity<UserInfo> response =
|
||||||
if (isValid() && isLoggedIn()) {
|
this.restTemplate
|
||||||
final ResponseEntity<UserInfo> response =
|
.getForEntity(this.currentUserURI, UserInfo.class);
|
||||||
this.restTemplate
|
if (response.getStatusCode() == HttpStatus.OK) {
|
||||||
.getForEntity(this.currentUserURI, UserInfo.class);
|
this.loggedInUser = Result.of(response.getBody());
|
||||||
if (response.getStatusCode() == HttpStatus.OK) {
|
return this.loggedInUser;
|
||||||
this.loggedInUser = Result.of(response.getBody());
|
} else {
|
||||||
return this.loggedInUser;
|
log.error("Unexpected error response: {}", response);
|
||||||
} else {
|
return Result.ofError(new IllegalStateException(
|
||||||
log.error("Unexpected error response: {}", response);
|
"Http Request responded with status: " + response.getStatusCode()));
|
||||||
return Result.ofError(new IllegalStateException(
|
}
|
||||||
"Http Request responded with status: " + response.getStatusCode()));
|
} else {
|
||||||
}
|
return Result.ofError(
|
||||||
} else {
|
new IllegalStateException("Logged in User requested on invalid or not logged in "));
|
||||||
return Result.ofError(
|
}
|
||||||
new IllegalStateException("Logged in User requested on invalid or not logged in "));
|
} catch (final AccessDeniedException | OAuth2AccessDeniedException ade) {
|
||||||
}
|
log.error("Acccess denied while trying to request logged in User from API", ade);
|
||||||
} catch (final AccessDeniedException | OAuth2AccessDeniedException ade) {
|
return Result.ofError(ade);
|
||||||
log.error("Acccess denied while trying to request logged in User from API", ade);
|
} catch (final Exception e) {
|
||||||
return Result.ofError(ade);
|
log.error("Unexpected error while trying to request logged in User from API", e);
|
||||||
} catch (final Exception e) {
|
return Result.ofError(
|
||||||
log.error("Unexpected error while trying to request logged in User from API", e);
|
new RuntimeException("Unexpected error while trying to request logged in User from API", e));
|
||||||
return Result.ofError(
|
}
|
||||||
new RuntimeException("Unexpected error while trying to request logged in User from API", e));
|
}
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
|
public boolean hasRole(final UserRole role) {
|
||||||
@Override
|
if (!isValid() || !isLoggedIn()) {
|
||||||
public boolean hasRole(final UserRole role) {
|
return false;
|
||||||
if (!isValid() || !isLoggedIn()) {
|
}
|
||||||
return false;
|
|
||||||
}
|
return getLoggedInUser()
|
||||||
|
.getOrThrow().roles
|
||||||
return getLoggedInUser()
|
.contains(role.name());
|
||||||
.getOrThrow().roles
|
}
|
||||||
.contains(role.name());
|
|
||||||
}
|
private static final class ErrorHandler extends OAuth2ErrorHandler {
|
||||||
|
private ErrorHandler(final OAuth2ProtectedResourceDetails resource) {
|
||||||
private static final class ErrorHandler extends OAuth2ErrorHandler {
|
super(resource);
|
||||||
private ErrorHandler(final OAuth2ProtectedResourceDetails resource) {
|
}
|
||||||
super(resource);
|
|
||||||
}
|
@Override
|
||||||
|
public boolean hasError(final ClientHttpResponse response) throws IOException {
|
||||||
@Override
|
try {
|
||||||
public boolean hasError(final ClientHttpResponse response) throws IOException {
|
final HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
|
||||||
try {
|
return (statusCode != null && statusCode.series().equals(HttpStatus.Series.SERVER_ERROR));
|
||||||
final HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
|
} catch (final Exception e) {
|
||||||
return (statusCode != null && statusCode.series().equals(HttpStatus.Series.SERVER_ERROR));
|
log.error("Unexpected: ", e);
|
||||||
} catch (final Exception e) {
|
return super.hasError(response);
|
||||||
log.error("Unexpected: ", e);
|
}
|
||||||
return super.hasError(response);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,66 +1,66 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
||||||
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
/** Defines functionality for the SEB Server webservice authorization context used to
|
/** Defines functionality for the SEB Server webservice authorization context used to
|
||||||
* manage a user session on GUI service. */
|
* manage a user session on GUI service. */
|
||||||
public interface SEBServerAuthorizationContext {
|
public interface SEBServerAuthorizationContext {
|
||||||
|
|
||||||
/** Indicates if this authorization context is still valid
|
/** Indicates if this authorization context is still valid
|
||||||
*
|
*
|
||||||
* @return true if the SEBServerAuthorizationContext is valid. False of not. */
|
* @return true if the SEBServerAuthorizationContext is valid. False of not. */
|
||||||
boolean isValid();
|
boolean isValid();
|
||||||
|
|
||||||
/** Indicated whether a user is logged in within this authorization context or not.
|
/** Indicated whether a user is logged in within this authorization context or not.
|
||||||
*
|
*
|
||||||
* @return whether a user is logged in within this authorization context or not */
|
* @return whether a user is logged in within this authorization context or not */
|
||||||
boolean isLoggedIn();
|
boolean isLoggedIn();
|
||||||
|
|
||||||
/** Requests a login with username and password on SEB Server webservice.
|
/** Requests a login with username and password on SEB Server webservice.
|
||||||
* This uses OAuth 2 and Springs OAuth2RestTemplate to exchange user/client credentials
|
* This uses OAuth 2 and Springs OAuth2RestTemplate to exchange user/client credentials
|
||||||
* with an access and refresh token.
|
* with an access and refresh token.
|
||||||
*
|
*
|
||||||
* @param username the username for login
|
* @param username the username for login
|
||||||
* @param password the password for login
|
* @param password the password for login
|
||||||
* @return */
|
* @return true if login was successful, false if no */
|
||||||
boolean login(String username, CharSequence password);
|
boolean login(String username, CharSequence password);
|
||||||
|
|
||||||
/** Requests a logout on SEB Server webservice if a user is currently logged in
|
/** Requests a logout on SEB Server webservice if a user is currently logged in
|
||||||
* This uses OAuth 2 and Springs OAuth2RestTemplate to make a revoke token request for the
|
* This uses OAuth 2 and Springs OAuth2RestTemplate to make a revoke token request for the
|
||||||
* currently logged in user and also invalidates this SEBServerAuthorizationContext
|
* currently logged in user and also invalidates this SEBServerAuthorizationContext
|
||||||
*
|
*
|
||||||
* @return true if logout was successful */
|
* @return true if logout was successful */
|
||||||
boolean logout();
|
boolean logout();
|
||||||
|
|
||||||
/** Gets a Result of the UserInfo data of currently logged in user or of an error if no user is logged in
|
/** Gets a Result of the UserInfo data of currently logged in user or of an error if no user is logged in
|
||||||
* or there was an unexpected error while trying to get the user information.
|
* or there was an unexpected error while trying to get the user information.
|
||||||
*
|
*
|
||||||
* @return Result of logged in user data or of an error on fail */
|
* @return Result of logged in user data or of an error on fail */
|
||||||
Result<UserInfo> getLoggedInUser();
|
Result<UserInfo> getLoggedInUser();
|
||||||
|
|
||||||
void refreshUser(UserInfo userInfo);
|
void refreshUser(UserInfo userInfo);
|
||||||
|
|
||||||
/** Returns true if a current logged in user has the specified role.
|
/** Returns true if a current logged in user has the specified role.
|
||||||
*
|
*
|
||||||
* @param role the UserRole to check
|
* @param role the UserRole to check
|
||||||
* @return true if a current logged in user has the specified role */
|
* @return true if a current logged in user has the specified role */
|
||||||
boolean hasRole(UserRole role);
|
boolean hasRole(UserRole role);
|
||||||
|
|
||||||
/** Get the underling RestTemplate to connect and communicate with the SEB Server webservice.
|
/** Get the underling RestTemplate to connect and communicate with the SEB Server webservice.
|
||||||
*
|
*
|
||||||
* @return the underling RestTemplate to connect and communicate with the SEB Server webservice */
|
* @return the underling RestTemplate to connect and communicate with the SEB Server webservice */
|
||||||
RestTemplate getRestTemplate();
|
RestTemplate getRestTemplate();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,114 +1,114 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
||||||
|
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
public class WebserviceConnectionData {
|
public class WebserviceConnectionData {
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
final String webserviceProtocol;
|
final String webserviceProtocol;
|
||||||
final String webserviceServerAdress;
|
final String webserviceServerAddress;
|
||||||
final String webserviceServerPort;
|
final String webserviceServerPort;
|
||||||
final String webserviceAPIPath;
|
final String webserviceAPIPath;
|
||||||
final String webserviceServerAddress;
|
final String webserviceServerURL;
|
||||||
|
|
||||||
private final UriComponentsBuilder webserviceURIBuilder;
|
private final UriComponentsBuilder webserviceURIBuilder;
|
||||||
|
|
||||||
protected WebserviceConnectionData(
|
protected WebserviceConnectionData(
|
||||||
final String id,
|
final String id,
|
||||||
final String webserviceProtocol,
|
final String webserviceProtocol,
|
||||||
final String webserviceServerAdress,
|
final String webserviceServerAddress,
|
||||||
final String webserviceServerPort,
|
final String webserviceServerPort,
|
||||||
final String webserviceAPIPath) {
|
final String webserviceAPIPath) {
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.webserviceProtocol = webserviceProtocol;
|
this.webserviceProtocol = webserviceProtocol;
|
||||||
this.webserviceServerAdress = webserviceServerAdress;
|
this.webserviceServerAddress = webserviceServerAddress;
|
||||||
this.webserviceServerPort = webserviceServerPort;
|
this.webserviceServerPort = webserviceServerPort;
|
||||||
this.webserviceAPIPath = webserviceAPIPath;
|
this.webserviceAPIPath = webserviceAPIPath;
|
||||||
|
|
||||||
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort;
|
this.webserviceServerURL = webserviceProtocol + "://" + webserviceServerAddress + ":" + webserviceServerPort;
|
||||||
this.webserviceURIBuilder = UriComponentsBuilder
|
this.webserviceURIBuilder = UriComponentsBuilder
|
||||||
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress)
|
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAddress)
|
||||||
.port(webserviceServerPort)
|
.port(webserviceServerPort)
|
||||||
.path(webserviceAPIPath);
|
.path(webserviceAPIPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebserviceProtocol() {
|
public String getWebserviceProtocol() {
|
||||||
return this.webserviceProtocol;
|
return this.webserviceProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebserviceServerAdress() {
|
public String getWebserviceServerAddress() {
|
||||||
return this.webserviceServerAdress;
|
return this.webserviceServerAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebserviceServerPort() {
|
public String getWebserviceServerPort() {
|
||||||
return this.webserviceServerPort;
|
return this.webserviceServerPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebserviceAPIPath() {
|
public String getWebserviceAPIPath() {
|
||||||
return this.webserviceAPIPath;
|
return this.webserviceAPIPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebserviceServerAddress() {
|
public String getWebserviceServerURL() {
|
||||||
return this.webserviceServerAddress;
|
return this.webserviceServerURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UriComponentsBuilder getWebserviceURIBuilder() {
|
public UriComponentsBuilder getWebserviceURIBuilder() {
|
||||||
return this.webserviceURIBuilder.cloneBuilder();
|
return this.webserviceURIBuilder.cloneBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
|
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) {
|
public boolean equals(final Object obj) {
|
||||||
if (this == obj)
|
if (this == obj)
|
||||||
return true;
|
return true;
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
final WebserviceConnectionData other = (WebserviceConnectionData) obj;
|
final WebserviceConnectionData other = (WebserviceConnectionData) obj;
|
||||||
if (this.id == null) {
|
if (this.id == null) {
|
||||||
if (other.id != null)
|
if (other.id != null)
|
||||||
return false;
|
return false;
|
||||||
} else if (!this.id.equals(other.id))
|
} else if (!this.id.equals(other.id))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
builder.append("WebserviceConnectionData [id=");
|
builder.append("WebserviceConnectionData [id=");
|
||||||
builder.append(this.id);
|
builder.append(this.id);
|
||||||
builder.append(", webserviceProtocol=");
|
builder.append(", webserviceProtocol=");
|
||||||
builder.append(this.webserviceProtocol);
|
builder.append(this.webserviceProtocol);
|
||||||
builder.append(", webserviceServerAdress=");
|
builder.append(", webserviceServerAddress=");
|
||||||
builder.append(this.webserviceServerAdress);
|
builder.append(this.webserviceServerAddress);
|
||||||
builder.append(", webserviceServerPort=");
|
builder.append(", webserviceServerPort=");
|
||||||
builder.append(this.webserviceServerPort);
|
builder.append(this.webserviceServerPort);
|
||||||
builder.append(", webserviceAPIPath=");
|
builder.append(", webserviceAPIPath=");
|
||||||
builder.append(this.webserviceAPIPath);
|
builder.append(this.webserviceAPIPath);
|
||||||
builder.append("]");
|
builder.append("]");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,69 +1,69 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class WebserviceURIService {
|
public class WebserviceURIService {
|
||||||
|
|
||||||
private final String servletContextPath;
|
private final String servletContextPath;
|
||||||
private final String webserviceServerAddress;
|
private final String webserviceServerAddress;
|
||||||
private final UriComponentsBuilder webserviceURIBuilder;
|
private final UriComponentsBuilder webserviceURIBuilder;
|
||||||
|
|
||||||
public WebserviceURIService(
|
public WebserviceURIService(
|
||||||
@Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol,
|
@Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol,
|
||||||
@Value("${sebserver.gui.webservice.address}") final String webserviceServerAdress,
|
@Value("${sebserver.gui.webservice.address}") final String webserviceServerAddress,
|
||||||
@Value("${sebserver.gui.webservice.port}") final String webserviceServerPort,
|
@Value("${sebserver.gui.webservice.port}") final String webserviceServerPort,
|
||||||
@Value("${server.servlet.context-path}") final String servletContextPath,
|
@Value("${server.servlet.context-path}") final String servletContextPath,
|
||||||
@Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) {
|
@Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) {
|
||||||
|
|
||||||
this.servletContextPath = servletContextPath;
|
this.servletContextPath = servletContextPath;
|
||||||
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort;
|
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAddress + ":" + webserviceServerPort;
|
||||||
this.webserviceURIBuilder = UriComponentsBuilder
|
this.webserviceURIBuilder = UriComponentsBuilder
|
||||||
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress)
|
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAddress)
|
||||||
.port(webserviceServerPort)
|
.port(webserviceServerPort)
|
||||||
.path(servletContextPath)
|
.path(servletContextPath)
|
||||||
.path(webserviceAPIPath);
|
.path(webserviceAPIPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebserviceServerAddress() {
|
public String getWebserviceServerAddress() {
|
||||||
return this.webserviceServerAddress;
|
return this.webserviceServerAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UriComponentsBuilder getURIBuilder() {
|
public UriComponentsBuilder getURIBuilder() {
|
||||||
return this.webserviceURIBuilder.cloneBuilder();
|
return this.webserviceURIBuilder.cloneBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOAuthTokenURI() {
|
public String getOAuthTokenURI() {
|
||||||
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
||||||
.path(this.servletContextPath)
|
.path(this.servletContextPath)
|
||||||
.path(API.OAUTH_TOKEN_ENDPOINT)
|
.path(API.OAUTH_TOKEN_ENDPOINT)
|
||||||
.toUriString();
|
.toUriString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOAuthRevokeTokenURI() {
|
public String getOAuthRevokeTokenURI() {
|
||||||
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
||||||
.path(this.servletContextPath)
|
.path(this.servletContextPath)
|
||||||
.path(API.OAUTH_REVOKE_TOKEN_ENDPOINT)
|
.path(API.OAUTH_REVOKE_TOKEN_ENDPOINT)
|
||||||
.toUriString();
|
.toUriString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCurrentUserRequestURI() {
|
public String getCurrentUserRequestURI() {
|
||||||
return getURIBuilder()
|
return getURIBuilder()
|
||||||
.path(API.CURRENT_USER_ENDPOINT)
|
.path(API.CURRENT_USER_ENDPOINT)
|
||||||
.toUriString();
|
.toUriString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,12 +49,10 @@ public class ClientConnectionDetails {
|
||||||
|
|
||||||
private static final int NUMBER_OF_NONE_INDICATOR_ROWS = 3;
|
private static final int NUMBER_OF_NONE_INDICATOR_ROWS = 3;
|
||||||
|
|
||||||
private final PageService pageService;
|
|
||||||
private final ResourceService resourceService;
|
private final ResourceService resourceService;
|
||||||
private final Exam exam;
|
|
||||||
private final EnumMap<IndicatorType, IndicatorData> indicatorMapping;
|
private final EnumMap<IndicatorType, IndicatorData> indicatorMapping;
|
||||||
private final RestCall<ClientConnectionData>.RestCallBuilder restCallBuilder;
|
private final RestCall<ClientConnectionData>.RestCallBuilder restCallBuilder;
|
||||||
private final FormHandle<?> formhandle;
|
private final FormHandle<?> formHandle;
|
||||||
private final ColorData colorData;
|
private final ColorData colorData;
|
||||||
|
|
||||||
private ClientConnectionData connectionData = null;
|
private ClientConnectionData connectionData = null;
|
||||||
|
@ -69,9 +67,7 @@ public class ClientConnectionDetails {
|
||||||
|
|
||||||
final Display display = pageContext.getRoot().getDisplay();
|
final Display display = pageContext.getRoot().getDisplay();
|
||||||
|
|
||||||
this.pageService = pageService;
|
|
||||||
this.resourceService = pageService.getResourceService();
|
this.resourceService = pageService.getResourceService();
|
||||||
this.exam = exam;
|
|
||||||
this.restCallBuilder = restCallBuilder;
|
this.restCallBuilder = restCallBuilder;
|
||||||
this.colorData = new ColorData(display);
|
this.colorData = new ColorData(display);
|
||||||
this.indicatorMapping = IndicatorData.createFormIndicators(
|
this.indicatorMapping = IndicatorData.createFormIndicators(
|
||||||
|
@ -80,12 +76,12 @@ public class ClientConnectionDetails {
|
||||||
this.colorData,
|
this.colorData,
|
||||||
NUMBER_OF_NONE_INDICATOR_ROWS);
|
NUMBER_OF_NONE_INDICATOR_ROWS);
|
||||||
|
|
||||||
final FormBuilder formBuilder = this.pageService.formBuilder(pageContext)
|
final FormBuilder formBuilder = pageService.formBuilder(pageContext)
|
||||||
.readonly(true)
|
.readonly(true)
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
QuizData.QUIZ_ATTR_NAME,
|
QuizData.QUIZ_ATTR_NAME,
|
||||||
EXAM_NAME_TEXT_KEY,
|
EXAM_NAME_TEXT_KEY,
|
||||||
this.exam.getName()))
|
exam.getName()))
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
|
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
|
||||||
CONNECTION_ID_TEXT_KEY,
|
CONNECTION_ID_TEXT_KEY,
|
||||||
|
@ -112,7 +108,7 @@ public class ClientConnectionDetails {
|
||||||
.withDefaultLabel(indData.indicator.name))
|
.withDefaultLabel(indData.indicator.name))
|
||||||
.addEmptyCell());
|
.addEmptyCell());
|
||||||
|
|
||||||
this.formhandle = formBuilder.build();
|
this.formHandle = formBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateData() {
|
public void updateData() {
|
||||||
|
@ -136,7 +132,7 @@ public class ClientConnectionDetails {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Form form = this.formhandle.getForm();
|
final Form form = this.formHandle.getForm();
|
||||||
form.setFieldValue(
|
form.setFieldValue(
|
||||||
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
|
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
|
||||||
this.connectionData.clientConnection.userSessionId);
|
this.connectionData.clientConnection.userSessionId);
|
||||||
|
|
|
@ -371,7 +371,7 @@ public final class ClientConnectionTable {
|
||||||
private void sortTable() {
|
private void sortTable() {
|
||||||
this.tableMapping = this.tableMapping.entrySet()
|
this.tableMapping = this.tableMapping.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue()))
|
.sorted(Entry.comparingByValue())
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
Entry::getKey,
|
Entry::getKey,
|
||||||
Entry::getValue,
|
Entry::getValue,
|
||||||
|
@ -398,13 +398,12 @@ public final class ClientConnectionTable {
|
||||||
final String attribute = this.resourceService
|
final String attribute = this.resourceService
|
||||||
.getCurrentUser()
|
.getCurrentUser()
|
||||||
.getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE);
|
.getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE);
|
||||||
|
this.statusFilter.clear();
|
||||||
if (attribute != null) {
|
if (attribute != null) {
|
||||||
this.statusFilter.clear();
|
|
||||||
Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR))
|
Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR))
|
||||||
.forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name)));
|
.forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name)));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.statusFilter.clear();
|
|
||||||
this.statusFilter.add(ConnectionStatus.DISABLED);
|
this.statusFilter.add(ConnectionStatus.DISABLED);
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
|
|
@ -1,100 +1,99 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.session;
|
package ch.ethz.seb.sebserver.gui.service.session;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
import java.util.Collection;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
|
||||||
import java.util.Collections;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
||||||
import java.util.EnumMap;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
import org.eclipse.swt.graphics.Color;
|
import org.eclipse.swt.widgets.Display;
|
||||||
import org.eclipse.swt.widgets.Display;
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
import java.util.Collection;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
|
import java.util.Comparator;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
|
import java.util.EnumMap;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
|
||||||
|
final class IndicatorData {
|
||||||
final class IndicatorData {
|
|
||||||
|
final int index;
|
||||||
final int index;
|
final int tableIndex;
|
||||||
final int tableIndex;
|
final Indicator indicator;
|
||||||
final Indicator indicator;
|
final Color defaultColor;
|
||||||
final Color defaultColor;
|
final Color defaultTextColor;
|
||||||
final Color defaultTextColor;
|
final ThresholdColor[] thresholdColor;
|
||||||
final ThresholdColor[] thresholdColor;
|
|
||||||
|
protected IndicatorData(
|
||||||
protected IndicatorData(
|
final Indicator indicator,
|
||||||
final Indicator indicator,
|
final int index,
|
||||||
final int index,
|
final int tableIndex,
|
||||||
final int tableIndex,
|
final ColorData colorData,
|
||||||
final ColorData colorData,
|
final Display display) {
|
||||||
final Display display) {
|
|
||||||
|
this.indicator = indicator;
|
||||||
this.indicator = indicator;
|
this.index = index;
|
||||||
this.index = index;
|
this.tableIndex = tableIndex;
|
||||||
this.tableIndex = tableIndex;
|
this.defaultColor = new Color(display, Utils.toRGB(indicator.defaultColor), 255);
|
||||||
this.defaultColor = new Color(display, Utils.toRGB(indicator.defaultColor), 255);
|
this.defaultTextColor = Utils.darkColor(this.defaultColor.getRGB())
|
||||||
this.defaultTextColor = Utils.darkColor(this.defaultColor.getRGB())
|
? colorData.darkColor
|
||||||
? colorData.darkColor
|
: colorData.lightColor;
|
||||||
: colorData.lightColor;
|
|
||||||
|
this.thresholdColor = new ThresholdColor[indicator.thresholds.size()];
|
||||||
this.thresholdColor = new ThresholdColor[indicator.thresholds.size()];
|
final ArrayList<Threshold> sortedThresholds = new ArrayList<>(indicator.thresholds);
|
||||||
final ArrayList<Threshold> sortedThresholds = new ArrayList<>(indicator.thresholds);
|
sortedThresholds.sort(Comparator.comparing(t -> t.value));
|
||||||
Collections.sort(sortedThresholds, (t1, t2) -> t1.value.compareTo(t2.value));
|
for (int i = 0; i < indicator.thresholds.size(); i++) {
|
||||||
for (int i = 0; i < indicator.thresholds.size(); i++) {
|
this.thresholdColor[i] = new ThresholdColor(sortedThresholds.get(i), display, colorData);
|
||||||
this.thresholdColor[i] = new ThresholdColor(sortedThresholds.get(i), display, colorData);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
static EnumMap<IndicatorType, IndicatorData> createFormIndicators(
|
||||||
static final EnumMap<IndicatorType, IndicatorData> createFormIndicators(
|
final Collection<Indicator> indicators,
|
||||||
final Collection<Indicator> indicators,
|
final Display display,
|
||||||
final Display display,
|
final ColorData colorData,
|
||||||
final ColorData colorData,
|
final int tableIndexOffset) {
|
||||||
final int tableIndexOffset) {
|
|
||||||
|
final EnumMap<IndicatorType, IndicatorData> indicatorMapping = new EnumMap<>(IndicatorType.class);
|
||||||
final EnumMap<IndicatorType, IndicatorData> indicatorMapping = new EnumMap<>(IndicatorType.class);
|
int i = 0;
|
||||||
int i = 0;
|
for (final Indicator indicator : indicators) {
|
||||||
for (final Indicator indicator : indicators) {
|
indicatorMapping.put(indicator.type, new IndicatorData(
|
||||||
indicatorMapping.put(indicator.type, new IndicatorData(
|
indicator,
|
||||||
indicator,
|
i,
|
||||||
i,
|
i + tableIndexOffset,
|
||||||
i + tableIndexOffset,
|
colorData,
|
||||||
colorData,
|
display));
|
||||||
display));
|
i++;
|
||||||
i++;
|
}
|
||||||
}
|
return indicatorMapping;
|
||||||
return indicatorMapping;
|
}
|
||||||
}
|
|
||||||
|
static int getWeight(final IndicatorData indicatorData, final double value) {
|
||||||
static final int getWeight(final IndicatorData indicatorData, final double value) {
|
for (int j = 0; j < indicatorData.thresholdColor.length; j++) {
|
||||||
for (int j = 0; j < indicatorData.thresholdColor.length; j++) {
|
if (value < indicatorData.thresholdColor[j].value) {
|
||||||
if (value < indicatorData.thresholdColor[j].value) {
|
return (j == 0) ? -1 : j - 1;
|
||||||
return (j == 0) ? -1 : j - 1;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return indicatorData.thresholdColor.length - 1;
|
||||||
return indicatorData.thresholdColor.length - 1;
|
}
|
||||||
}
|
|
||||||
|
static final class ThresholdColor {
|
||||||
static final class ThresholdColor {
|
final double value;
|
||||||
final double value;
|
final Color color;
|
||||||
final Color color;
|
final Color textColor;
|
||||||
final Color textColor;
|
|
||||||
|
protected ThresholdColor(final Threshold threshold, final Display display, final ColorData colorData) {
|
||||||
protected ThresholdColor(final Threshold threshold, final Display display, final ColorData colorData) {
|
this.value = threshold.value;
|
||||||
this.value = threshold.value;
|
this.color = new Color(display, Utils.toRGB(threshold.color), 255);
|
||||||
this.color = new Color(display, Utils.toRGB(threshold.color), 255);
|
this.textColor = Utils.darkColor(this.color.getRGB())
|
||||||
this.textColor = Utils.darkColor(this.color.getRGB())
|
? colorData.darkColor
|
||||||
? colorData.darkColor
|
: colorData.lightColor;
|
||||||
: colorData.lightColor;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,165 +1,160 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.service.session;
|
package ch.ethz.seb.sebserver.gui.service.session;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.DisableClientConnection;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.DisableClientConnection;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.PropagateInstruction;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.PropagateInstruction;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Service
|
@Service
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class InstructionProcessor {
|
public class InstructionProcessor {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(InstructionProcessor.class);
|
private static final Logger log = LoggerFactory.getLogger(InstructionProcessor.class);
|
||||||
|
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
private final JSONMapper jsonMapper;
|
private final JSONMapper jsonMapper;
|
||||||
|
|
||||||
protected InstructionProcessor(final PageService pageService) {
|
protected InstructionProcessor(final PageService pageService) {
|
||||||
this.restService = pageService.getRestService();
|
this.restService = pageService.getRestService();
|
||||||
this.jsonMapper = pageService.getJSONMapper();
|
this.jsonMapper = pageService.getJSONMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void propagateSebQuitInstruction(
|
public void propagateSebQuitInstruction(
|
||||||
final Long examId,
|
final Long examId,
|
||||||
final String connectionToken,
|
final String connectionToken,
|
||||||
final PageContext pageContext) {
|
final PageContext pageContext) {
|
||||||
|
|
||||||
propagateSebQuitInstruction(
|
propagateSebQuitInstruction(
|
||||||
examId,
|
examId,
|
||||||
p -> Stream.of(connectionToken).collect(Collectors.toSet()),
|
p -> Stream.of(connectionToken).collect(Collectors.toSet()),
|
||||||
pageContext);
|
pageContext);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void propagateSebQuitInstruction(
|
public void propagateSebQuitInstruction(
|
||||||
final Long examId,
|
final Long examId,
|
||||||
final Function<Predicate<ClientConnection>, Set<String>> selectionFunction,
|
final Function<Predicate<ClientConnection>, Set<String>> selectionFunction,
|
||||||
final PageContext pageContext) {
|
final PageContext pageContext) {
|
||||||
|
|
||||||
final Set<String> connectionTokens = selectionFunction
|
final Set<String> connectionTokens = selectionFunction
|
||||||
.apply(ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE));
|
.apply(ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE));
|
||||||
|
|
||||||
if (connectionTokens.isEmpty()) {
|
if (connectionTokens.isEmpty()) {
|
||||||
// TODO message
|
// TODO message
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Propagate SEB quit instruction for exam: {} and connections: {}",
|
log.debug("Propagate SEB quit instruction for exam: {} and connections: {}",
|
||||||
examId,
|
examId,
|
||||||
connectionTokens);
|
connectionTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ClientInstruction clientInstruction = new ClientInstruction(
|
final ClientInstruction clientInstruction = new ClientInstruction(
|
||||||
null,
|
null,
|
||||||
examId,
|
examId,
|
||||||
InstructionType.SEB_QUIT,
|
InstructionType.SEB_QUIT,
|
||||||
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR),
|
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR),
|
||||||
null);
|
null);
|
||||||
|
|
||||||
processInstruction(() -> {
|
processInstruction(() -> this.restService.getBuilder(PropagateInstruction.class)
|
||||||
return this.restService.getBuilder(PropagateInstruction.class)
|
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId))
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId))
|
.withBody(clientInstruction)
|
||||||
.withBody(clientInstruction)
|
.call()
|
||||||
.call()
|
.getOrThrow(),
|
||||||
.getOrThrow();
|
pageContext);
|
||||||
},
|
|
||||||
pageContext);
|
}
|
||||||
|
|
||||||
}
|
public void disableConnection(
|
||||||
|
final Long examId,
|
||||||
public void disableConnection(
|
final Function<Predicate<ClientConnection>, Set<String>> selectionFunction,
|
||||||
final Long examId,
|
final PageContext pageContext) {
|
||||||
final Function<Predicate<ClientConnection>, Set<String>> selectionFunction,
|
|
||||||
final PageContext pageContext) {
|
final Set<String> connectionTokens = selectionFunction
|
||||||
|
.apply(ClientConnection.getStatusPredicate(
|
||||||
final Set<String> connectionTokens = selectionFunction
|
ConnectionStatus.CONNECTION_REQUESTED,
|
||||||
.apply(ClientConnection.getStatusPredicate(
|
ConnectionStatus.UNDEFINED,
|
||||||
ConnectionStatus.CONNECTION_REQUESTED,
|
ConnectionStatus.CLOSED,
|
||||||
ConnectionStatus.UNDEFINED,
|
ConnectionStatus.AUTHENTICATED));
|
||||||
ConnectionStatus.CLOSED,
|
|
||||||
ConnectionStatus.AUTHENTICATED));
|
if (connectionTokens.isEmpty()) {
|
||||||
|
return;
|
||||||
if (connectionTokens.isEmpty()) {
|
}
|
||||||
// TOOD message
|
|
||||||
return;
|
if (log.isDebugEnabled()) {
|
||||||
}
|
log.debug("Disable SEB client connections for exam: {} and connections: {}",
|
||||||
|
examId,
|
||||||
if (log.isDebugEnabled()) {
|
connectionTokens);
|
||||||
log.debug("Disable SEB client connections for exam: {} and connections: {}",
|
}
|
||||||
examId,
|
|
||||||
connectionTokens);
|
processInstruction(() -> this.restService.getBuilder(DisableClientConnection.class)
|
||||||
}
|
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId))
|
||||||
|
.withFormParam(
|
||||||
processInstruction(() -> {
|
Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN,
|
||||||
return this.restService.getBuilder(DisableClientConnection.class)
|
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR))
|
||||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId))
|
.call()
|
||||||
.withFormParam(
|
.getOrThrow(),
|
||||||
Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN,
|
pageContext);
|
||||||
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR))
|
|
||||||
.call()
|
}
|
||||||
.getOrThrow();
|
|
||||||
},
|
private void processInstruction(final Supplier<String> apiCall, final PageContext pageContext) {
|
||||||
pageContext);
|
try {
|
||||||
|
final String response = apiCall.get();
|
||||||
}
|
|
||||||
|
if (StringUtils.isNotBlank(response)) {
|
||||||
private void processInstruction(final Supplier<String> apiCall, final PageContext pageContext) {
|
try {
|
||||||
try {
|
final Collection<APIMessage> errorMessage = this.jsonMapper.readValue(
|
||||||
final String response = apiCall.get();
|
response,
|
||||||
|
Constants.TYPE_REFERENCE_API_MESSAGE);
|
||||||
if (StringUtils.isNotBlank(response)) {
|
|
||||||
try {
|
pageContext.notifyUnexpectedError(new RestCallError(
|
||||||
final Collection<APIMessage> errorMessage = this.jsonMapper.readValue(
|
"Failed to propagate SEB client instruction: ",
|
||||||
response,
|
errorMessage));
|
||||||
Constants.TYPE_REFERENCE_API_MESSAGE);
|
|
||||||
|
} catch (final Exception e) {
|
||||||
pageContext.notifyUnexpectedError(new RestCallError(
|
log.error("Failed to parse error response: {}", response);
|
||||||
"Failed to propagate SEB client instruction: ",
|
}
|
||||||
errorMessage));
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
} catch (final Exception e) {
|
log.error("Failed to propagate SEB client instruction: ", e);
|
||||||
log.error("Failed to parse error response: {}", response);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
}
|
||||||
log.error("Failed to propagate SEB client instruction: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,174 +1,174 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.table;
|
package ch.ethz.seb.sebserver.gui.table;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.widgets.TableItem;
|
import org.eclipse.swt.widgets.TableItem;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||||
|
|
||||||
public class TableBuilder<ROW extends Entity> {
|
public class TableBuilder<ROW extends Entity> {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
final RestCall<Page<ROW>> restCall;
|
final RestCall<Page<ROW>> restCall;
|
||||||
private final MultiValueMap<String, String> staticQueryParams;
|
private final MultiValueMap<String, String> staticQueryParams;
|
||||||
final List<ColumnDefinition<ROW>> columns = new ArrayList<>();
|
final List<ColumnDefinition<ROW>> columns = new ArrayList<>();
|
||||||
LocTextKey emptyMessage;
|
LocTextKey emptyMessage;
|
||||||
private Function<EntityTable<ROW>, PageAction> defaultActionFunction;
|
private Function<EntityTable<ROW>, PageAction> defaultActionFunction;
|
||||||
private int pageSize = -1;
|
private int pageSize = -1;
|
||||||
private int type = SWT.NONE;
|
private int type = SWT.NONE;
|
||||||
private boolean hideNavigation = false;
|
private boolean hideNavigation = false;
|
||||||
private Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter;
|
private Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter;
|
||||||
private BiConsumer<TableItem, ROW> rowDecorator;
|
private BiConsumer<TableItem, ROW> rowDecorator;
|
||||||
private Consumer<Set<ROW>> selectionListener;
|
private Consumer<Set<ROW>> selectionListener;
|
||||||
private boolean markupEnabled = false;
|
private boolean markupEnabled = false;
|
||||||
|
|
||||||
public TableBuilder(
|
public TableBuilder(
|
||||||
final String name,
|
final String name,
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final RestCall<Page<ROW>> restCall) {
|
final RestCall<Page<ROW>> restCall) {
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.pageService = pageService;
|
this.pageService = pageService;
|
||||||
this.restCall = restCall;
|
this.restCall = restCall;
|
||||||
this.staticQueryParams = new LinkedMultiValueMap<>();
|
this.staticQueryParams = new LinkedMultiValueMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> hideNavigation() {
|
public TableBuilder<ROW> hideNavigation() {
|
||||||
this.hideNavigation = true;
|
this.hideNavigation = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withEmptyMessage(final LocTextKey emptyMessage) {
|
public TableBuilder<ROW> withEmptyMessage(final LocTextKey emptyMessage) {
|
||||||
this.emptyMessage = emptyMessage;
|
this.emptyMessage = emptyMessage;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withPaging(final int pageSize) {
|
public TableBuilder<ROW> withPaging(final int pageSize) {
|
||||||
this.pageSize = pageSize;
|
this.pageSize = pageSize;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withColumn(final ColumnDefinition<ROW> columnDefinition) {
|
public TableBuilder<ROW> withColumn(final ColumnDefinition<ROW> columnDefinition) {
|
||||||
this.columns.add(columnDefinition);
|
this.columns.add(columnDefinition);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withMarkup() {
|
public TableBuilder<ROW> withMarkup() {
|
||||||
this.markupEnabled = true;
|
this.markupEnabled = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withColumnIf(
|
public TableBuilder<ROW> withColumnIf(
|
||||||
final BooleanSupplier condition,
|
final BooleanSupplier condition,
|
||||||
final Supplier<ColumnDefinition<ROW>> columnDefSupplier) {
|
final Supplier<ColumnDefinition<ROW>> columnDefSupplier) {
|
||||||
|
|
||||||
if (condition != null && condition.getAsBoolean()) {
|
if (condition != null && condition.getAsBoolean()) {
|
||||||
this.columns.add(columnDefSupplier.get());
|
this.columns.add(columnDefSupplier.get());
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withRestCallAdapter(
|
public TableBuilder<ROW> withRestCallAdapter(
|
||||||
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> adapter) {
|
final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> adapter) {
|
||||||
|
|
||||||
this.restCallAdapter = adapter;
|
this.restCallAdapter = adapter;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withMultiselection() {
|
public TableBuilder<ROW> withMultiSelection() {
|
||||||
this.type |= SWT.MULTI;
|
this.type |= SWT.MULTI;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withSelectionListener(final Consumer<Set<ROW>> selectionListener) {
|
public TableBuilder<ROW> withSelectionListener(final Consumer<Set<ROW>> selectionListener) {
|
||||||
this.selectionListener = selectionListener;
|
this.selectionListener = selectionListener;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withStaticFilter(final String name, final String value) {
|
public TableBuilder<ROW> withStaticFilter(final String name, final String value) {
|
||||||
this.staticQueryParams.add(name, value);
|
this.staticQueryParams.add(name, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withDefaultActionIf(
|
public TableBuilder<ROW> withDefaultActionIf(
|
||||||
final BooleanSupplier condition,
|
final BooleanSupplier condition,
|
||||||
final Supplier<PageAction> actionSupplier) {
|
final Supplier<PageAction> actionSupplier) {
|
||||||
|
|
||||||
if (condition.getAsBoolean()) {
|
if (condition.getAsBoolean()) {
|
||||||
return withDefaultAction(actionSupplier.get());
|
return withDefaultAction(actionSupplier.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withDefaultAction(final PageAction action) {
|
public TableBuilder<ROW> withDefaultAction(final PageAction action) {
|
||||||
this.defaultActionFunction = table -> PageAction.copyOf(action);
|
this.defaultActionFunction = table -> PageAction.copyOf(action);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withDefaultActionIf(
|
public TableBuilder<ROW> withDefaultActionIf(
|
||||||
final BooleanSupplier condition,
|
final BooleanSupplier condition,
|
||||||
final Function<EntityTable<ROW>, PageAction> defaultActionFunction) {
|
final Function<EntityTable<ROW>, PageAction> defaultActionFunction) {
|
||||||
|
|
||||||
if (condition.getAsBoolean()) {
|
if (condition.getAsBoolean()) {
|
||||||
return withDefaultAction(defaultActionFunction);
|
return withDefaultAction(defaultActionFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withDefaultAction(final Function<EntityTable<ROW>, PageAction> defaultActionFunction) {
|
public TableBuilder<ROW> withDefaultAction(final Function<EntityTable<ROW>, PageAction> defaultActionFunction) {
|
||||||
this.defaultActionFunction = defaultActionFunction;
|
this.defaultActionFunction = defaultActionFunction;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableBuilder<ROW> withRowDecorator(final BiConsumer<TableItem, ROW> rowDecorator) {
|
public TableBuilder<ROW> withRowDecorator(final BiConsumer<TableItem, ROW> rowDecorator) {
|
||||||
this.rowDecorator = rowDecorator;
|
this.rowDecorator = rowDecorator;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityTable<ROW> compose(final PageContext pageContext) {
|
public EntityTable<ROW> compose(final PageContext pageContext) {
|
||||||
return new EntityTable<>(
|
return new EntityTable<>(
|
||||||
this.name,
|
this.name,
|
||||||
this.markupEnabled,
|
this.markupEnabled,
|
||||||
this.type,
|
this.type,
|
||||||
pageContext,
|
pageContext,
|
||||||
this.restCall,
|
this.restCall,
|
||||||
this.restCallAdapter,
|
this.restCallAdapter,
|
||||||
this.pageService,
|
this.pageService,
|
||||||
this.columns,
|
this.columns,
|
||||||
this.pageSize,
|
this.pageSize,
|
||||||
this.emptyMessage,
|
this.emptyMessage,
|
||||||
this.defaultActionFunction,
|
this.defaultActionFunction,
|
||||||
this.hideNavigation,
|
this.hideNavigation,
|
||||||
this.staticQueryParams,
|
this.staticQueryParams,
|
||||||
this.rowDecorator,
|
this.rowDecorator,
|
||||||
this.selectionListener);
|
this.selectionListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to");
|
private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to");
|
||||||
private static final LocTextKey ALL_TEXT = new LocTextKey("sebserver.overall.status.all");
|
private static final LocTextKey ALL_TEXT = new LocTextKey("sebserver.overall.status.all");
|
||||||
|
|
||||||
public static enum CriteriaType {
|
public enum CriteriaType {
|
||||||
TEXT,
|
TEXT,
|
||||||
SINGLE_SELECTION,
|
SINGLE_SELECTION,
|
||||||
DATE,
|
DATE,
|
||||||
|
@ -82,7 +82,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
public MultiValueMap<String, String> getFilterParameter() {
|
public MultiValueMap<String, String> getFilterParameter() {
|
||||||
return this.components
|
return this.components
|
||||||
.stream()
|
.stream()
|
||||||
.reduce(new LinkedMultiValueMap<String, String>(),
|
.reduce(new LinkedMultiValueMap<>(),
|
||||||
(map, comp) -> comp.putFilterParameter(map),
|
(map, comp) -> comp.putFilterParameter(map),
|
||||||
(map1, map2) -> {
|
(map1, map2) -> {
|
||||||
map1.putAll(map2);
|
map1.putAll(map2);
|
||||||
|
@ -92,8 +92,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
this.components
|
this.components
|
||||||
.stream()
|
.forEach(FilterComponent::reset);
|
||||||
.forEach(comp -> comp.reset());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildComponents() {
|
private void buildComponents() {
|
||||||
|
@ -158,7 +157,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||||
.append(filter.getValue())
|
.append(filter.getValue())
|
||||||
.append(Constants.LIST_SEPARATOR),
|
.append(Constants.LIST_SEPARATOR),
|
||||||
(sb1, sb2) -> sb1.append(sb2));
|
StringBuilder::append);
|
||||||
if (builder.length() > 0) {
|
if (builder.length() > 0) {
|
||||||
builder.deleteCharAt(builder.length() - 1);
|
builder.deleteCharAt(builder.length() - 1);
|
||||||
}
|
}
|
||||||
|
@ -171,22 +170,19 @@ public class TableFilter<ROW extends Entity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Arrays.asList(StringUtils.split(
|
Arrays.stream(StringUtils.split(
|
||||||
attribute,
|
attribute,
|
||||||
Constants.LIST_SEPARATOR_CHAR))
|
Constants.LIST_SEPARATOR_CHAR))
|
||||||
.stream()
|
|
||||||
.map(nameValue -> StringUtils.split(
|
.map(nameValue -> StringUtils.split(
|
||||||
nameValue,
|
nameValue,
|
||||||
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
|
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
|
||||||
.forEach(nameValue -> {
|
.forEach(nameValue -> this.components
|
||||||
this.components
|
.stream()
|
||||||
.stream()
|
.filter(filter -> nameValue[0].equals(filter.attribute.columnName))
|
||||||
.filter(filter -> nameValue[0].equals(filter.attribute.columnName))
|
.findFirst()
|
||||||
.findFirst()
|
.ifPresent(filter -> filter.setValue((nameValue.length > 1)
|
||||||
.ifPresent(filter -> filter.setValue((nameValue.length > 1)
|
? nameValue[1]
|
||||||
? nameValue[1]
|
: StringUtils.EMPTY)));
|
||||||
: StringUtils.EMPTY));
|
|
||||||
});
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Failed to set filter attributes: ", e);
|
log.error("Failed to set filter attributes: ", e);
|
||||||
}
|
}
|
||||||
|
@ -208,9 +204,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
ImageIcon.SEARCH,
|
ImageIcon.SEARCH,
|
||||||
inner,
|
inner,
|
||||||
new LocTextKey("sebserver.overall.action.filter"),
|
new LocTextKey("sebserver.overall.action.filter"),
|
||||||
event -> {
|
event -> this.entityTable.applyFilter());
|
||||||
this.entityTable.applyFilter();
|
|
||||||
});
|
|
||||||
imageButton.setLayoutData(gridData);
|
imageButton.setLayoutData(gridData);
|
||||||
final Label imageButton2 = this.entityTable.widgetFactory.imageButton(
|
final Label imageButton2 = this.entityTable.widgetFactory.imageButton(
|
||||||
ImageIcon.CANCEL,
|
ImageIcon.CANCEL,
|
||||||
|
@ -276,7 +270,7 @@ public class TableFilter<ROW extends Entity> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NullFilter extends FilterComponent {
|
private static class NullFilter extends FilterComponent {
|
||||||
|
|
||||||
private Label label;
|
private Label label;
|
||||||
|
|
||||||
|
@ -493,7 +487,6 @@ public class TableFilter<ROW extends Entity> {
|
||||||
private class DateRange extends FilterComponent {
|
private class DateRange extends FilterComponent {
|
||||||
|
|
||||||
private Composite innerComposite;
|
private Composite innerComposite;
|
||||||
//private final GridData rw1 = new GridData(SWT.FILL, SWT.FILL, true, true);
|
|
||||||
private DateTime fromDateSelector;
|
private DateTime fromDateSelector;
|
||||||
private DateTime toDateSelector;
|
private DateTime toDateSelector;
|
||||||
private DateTime fromTimeSelector;
|
private DateTime fromTimeSelector;
|
||||||
|
|
|
@ -1,189 +1,179 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.table;
|
package ch.ethz.seb.sebserver.gui.table;
|
||||||
|
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||||
|
|
||||||
public class TableNavigator {
|
public class TableNavigator {
|
||||||
|
|
||||||
private final static int PAGE_NAV_SIZE = 9;
|
private final static int PAGE_NAV_SIZE = 9;
|
||||||
|
|
||||||
private final Composite composite;
|
private final Composite composite;
|
||||||
private final EntityTable<?> entityTable;
|
private final EntityTable<?> entityTable;
|
||||||
|
|
||||||
TableNavigator(final EntityTable<?> entityTable) {
|
TableNavigator(final EntityTable<?> entityTable) {
|
||||||
this.composite = new Composite(entityTable.composite, SWT.NONE);
|
this.composite = new Composite(entityTable.composite, SWT.NONE);
|
||||||
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
||||||
this.composite.setLayoutData(gridData);
|
this.composite.setLayoutData(gridData);
|
||||||
final GridLayout layout = new GridLayout(3, false);
|
final GridLayout layout = new GridLayout(3, false);
|
||||||
this.composite.setLayout(layout);
|
this.composite.setLayout(layout);
|
||||||
|
|
||||||
this.entityTable = entityTable;
|
this.entityTable = entityTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page<?> update(final Page<?> pageData) {
|
public Page<?> update(final Page<?> pageData) {
|
||||||
// clear all
|
// clear all
|
||||||
PageService.clearComposite(this.composite);
|
PageService.clearComposite(this.composite);
|
||||||
|
|
||||||
if (pageData.isEmpty()) {
|
if (pageData.isEmpty()) {
|
||||||
// show empty message
|
// show empty message
|
||||||
if (this.entityTable.emptyMessage != null) {
|
if (this.entityTable.emptyMessage != null) {
|
||||||
this.entityTable.widgetFactory.labelLocalized(
|
this.entityTable.widgetFactory.labelLocalized(
|
||||||
this.composite,
|
this.composite,
|
||||||
CustomVariant.TEXT_H3,
|
CustomVariant.TEXT_H3,
|
||||||
this.entityTable.emptyMessage);
|
this.entityTable.emptyMessage);
|
||||||
}
|
}
|
||||||
return pageData;
|
return pageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.entityTable.hideNavigation) {
|
if (this.entityTable.hideNavigation) {
|
||||||
return pageData;
|
return pageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int pageNumber = pageData.getPageNumber();
|
final int pageNumber = pageData.getPageNumber();
|
||||||
final int numberOfPages = pageData.getNumberOfPages();
|
final int numberOfPages = pageData.getNumberOfPages();
|
||||||
|
|
||||||
createPagingHeader(pageNumber, numberOfPages);
|
createPagingHeader(pageNumber, numberOfPages);
|
||||||
|
|
||||||
final Composite numNav = new Composite(this.composite, SWT.NONE);
|
final Composite numNav = new Composite(this.composite, SWT.NONE);
|
||||||
final GridData gridData = new GridData(SWT.CENTER, SWT.TOP, true, false);
|
final GridData gridData = new GridData(SWT.CENTER, SWT.TOP, true, false);
|
||||||
numNav.setLayoutData(gridData);
|
numNav.setLayoutData(gridData);
|
||||||
final GridLayout rowLayout = new GridLayout(PAGE_NAV_SIZE + 5, true);
|
final GridLayout rowLayout = new GridLayout(PAGE_NAV_SIZE + 5, true);
|
||||||
numNav.setLayout(rowLayout);
|
numNav.setLayout(rowLayout);
|
||||||
|
|
||||||
if (numberOfPages > 1) {
|
if (numberOfPages > 1) {
|
||||||
createBackwardLabel(pageNumber > 1, pageNumber, numNav);
|
createBackwardLabel(pageNumber > 1, pageNumber, numNav);
|
||||||
final int pageNavSize = (numberOfPages > PAGE_NAV_SIZE) ? PAGE_NAV_SIZE : numberOfPages;
|
final int pageNavSize = Math.min(numberOfPages, PAGE_NAV_SIZE);
|
||||||
final int half = pageNavSize / 2;
|
final int half = pageNavSize / 2;
|
||||||
int start = pageNumber - half;
|
int start = pageNumber - half;
|
||||||
if (start < 1) {
|
if (start < 1) {
|
||||||
start = 1;
|
start = 1;
|
||||||
}
|
}
|
||||||
int end = start + pageNavSize;
|
int end = start + pageNavSize;
|
||||||
if (end > numberOfPages) {
|
if (end > numberOfPages) {
|
||||||
end = numberOfPages + 1;
|
end = numberOfPages + 1;
|
||||||
start = end - pageNavSize;
|
start = end - pageNavSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
createPageNumberLabel(i, i != pageNumber, numNav);
|
createPageNumberLabel(i, i != pageNumber, numNav);
|
||||||
}
|
}
|
||||||
|
|
||||||
createForwardLabel(pageNumber < numberOfPages, pageNumber, numberOfPages, numNav);
|
createForwardLabel(pageNumber < numberOfPages, pageNumber, numberOfPages, numNav);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pageData;
|
return pageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPagingHeader(final int page, final int of) {
|
private void createPagingHeader(final int page, final int of) {
|
||||||
final Label pageHeader = new Label(this.composite, SWT.NONE);
|
final Label pageHeader = new Label(this.composite, SWT.NONE);
|
||||||
final GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, true, false);
|
final GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, true, false);
|
||||||
gridData.widthHint = 100;
|
gridData.widthHint = 100;
|
||||||
gridData.minimumWidth = 100;
|
gridData.minimumWidth = 100;
|
||||||
gridData.heightHint = 16;
|
gridData.heightHint = 16;
|
||||||
pageHeader.setLayoutData(gridData);
|
pageHeader.setLayoutData(gridData);
|
||||||
pageHeader.setText("Page " + page + " / " + of);
|
pageHeader.setText("Page " + page + " / " + of);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPageNumberLabel(
|
private void createPageNumberLabel(
|
||||||
final int page,
|
final int page,
|
||||||
final boolean selectable,
|
final boolean selectable,
|
||||||
final Composite parent) {
|
final Composite parent) {
|
||||||
|
|
||||||
final GridData rowData = new GridData(22, 16);
|
final GridData rowData = new GridData(22, 16);
|
||||||
final Label pageLabel = new Label(parent, SWT.NONE);
|
final Label pageLabel = new Label(parent, SWT.NONE);
|
||||||
pageLabel.setText(" " + String.valueOf(page) + " ");
|
pageLabel.setText(" " + page + " ");
|
||||||
pageLabel.setLayoutData(rowData);
|
pageLabel.setLayoutData(rowData);
|
||||||
pageLabel.setAlignment(SWT.CENTER);
|
pageLabel.setAlignment(SWT.CENTER);
|
||||||
if (selectable) {
|
if (selectable) {
|
||||||
pageLabel.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
pageLabel.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
||||||
pageLabel.addListener(SWT.MouseDown, event -> {
|
pageLabel.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(page));
|
||||||
this.entityTable.selectPage(page);
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
}
|
private void createForwardLabel(
|
||||||
|
final boolean visible,
|
||||||
private void createForwardLabel(
|
final int pageNumber,
|
||||||
final boolean visible,
|
final int numberOfPages,
|
||||||
final int pageNumber,
|
final Composite parent) {
|
||||||
final int numberOfPages,
|
|
||||||
final Composite parent) {
|
final GridData rowData = new GridData(22, 16);
|
||||||
|
final Label forward = new Label(parent, SWT.NONE);
|
||||||
final GridData rowData = new GridData(22, 16);
|
forward.setText(">");
|
||||||
final Label forward = new Label(parent, SWT.NONE);
|
forward.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
||||||
forward.setText(">");
|
forward.setLayoutData(rowData);
|
||||||
forward.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
forward.setAlignment(SWT.CENTER);
|
||||||
forward.setLayoutData(rowData);
|
if (visible) {
|
||||||
forward.setAlignment(SWT.CENTER);
|
forward.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(pageNumber + 1));
|
||||||
if (visible) {
|
} else {
|
||||||
forward.addListener(SWT.MouseDown, event -> {
|
forward.setVisible(false);
|
||||||
this.entityTable.selectPage(pageNumber + 1);
|
}
|
||||||
});
|
|
||||||
} else {
|
final Label end = new Label(parent, SWT.NONE);
|
||||||
forward.setVisible(false);
|
end.setText(">>");
|
||||||
}
|
end.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
||||||
|
end.setLayoutData(rowData);
|
||||||
final Label end = new Label(parent, SWT.NONE);
|
end.setAlignment(SWT.CENTER);
|
||||||
end.setText(">>");
|
if (visible) {
|
||||||
end.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
end.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(numberOfPages));
|
||||||
end.setLayoutData(rowData);
|
} else {
|
||||||
end.setAlignment(SWT.CENTER);
|
end.setVisible(false);
|
||||||
if (visible) {
|
}
|
||||||
end.addListener(SWT.MouseDown, event -> {
|
}
|
||||||
this.entityTable.selectPage(numberOfPages);
|
|
||||||
});
|
private void createBackwardLabel(
|
||||||
} else {
|
final boolean visible,
|
||||||
end.setVisible(false);
|
final int pageNumber,
|
||||||
}
|
final Composite parent) {
|
||||||
}
|
|
||||||
|
final GridData rowData = new GridData(22, 16);
|
||||||
private void createBackwardLabel(
|
final Label start = new Label(parent, SWT.NONE);
|
||||||
final boolean visible,
|
start.setText("<<");
|
||||||
final int pageNumber,
|
start.setLayoutData(rowData);
|
||||||
final Composite parent) {
|
start.setAlignment(SWT.CENTER);
|
||||||
|
start.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
||||||
final GridData rowData = new GridData(22, 16);
|
if (visible) {
|
||||||
final Label start = new Label(parent, SWT.NONE);
|
start.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(1));
|
||||||
start.setText("<<");
|
} else {
|
||||||
start.setLayoutData(rowData);
|
start.setVisible(false);
|
||||||
start.setAlignment(SWT.CENTER);
|
}
|
||||||
start.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
|
||||||
if (visible) {
|
final Label backward = new Label(parent, SWT.NONE);
|
||||||
start.addListener(SWT.MouseDown, event -> {
|
backward.setText("<");
|
||||||
this.entityTable.selectPage(1);
|
backward.setLayoutData(rowData);
|
||||||
});
|
backward.setAlignment(SWT.CENTER);
|
||||||
} else {
|
backward.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
||||||
start.setVisible(false);
|
if (visible) {
|
||||||
}
|
backward.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(pageNumber - 1));
|
||||||
|
} else {
|
||||||
final Label backward = new Label(parent, SWT.NONE);
|
backward.setVisible(false);
|
||||||
backward.setText("<");
|
}
|
||||||
backward.setLayoutData(rowData);
|
|
||||||
backward.setAlignment(SWT.CENTER);
|
}
|
||||||
backward.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
|
|
||||||
if (visible) {
|
}
|
||||||
backward.addListener(SWT.MouseDown, event -> {
|
|
||||||
this.entityTable.selectPage(pageNumber - 1);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
backward.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,204 +1,202 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PipedInputStream;
|
import java.io.PipedInputStream;
|
||||||
import java.io.PipedOutputStream;
|
import java.io.PipedOutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.eclipse.rap.fileupload.FileDetails;
|
import org.eclipse.rap.fileupload.FileDetails;
|
||||||
import org.eclipse.rap.fileupload.FileUploadHandler;
|
import org.eclipse.rap.fileupload.FileUploadHandler;
|
||||||
import org.eclipse.rap.fileupload.FileUploadReceiver;
|
import org.eclipse.rap.fileupload.FileUploadReceiver;
|
||||||
import org.eclipse.rap.rwt.widgets.FileUpload;
|
import org.eclipse.rap.rwt.widgets.FileUpload;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
|
|
||||||
public class FileUploadSelection extends Composite {
|
public class FileUploadSelection extends Composite {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FileUploadSelection.class);
|
private static final Logger log = LoggerFactory.getLogger(FileUploadSelection.class);
|
||||||
|
|
||||||
private static final long serialVersionUID = 5800153475027387363L;
|
private static final long serialVersionUID = 5800153475027387363L;
|
||||||
|
|
||||||
private static final LocTextKey PLEASE_SELECT_TEXT =
|
private static final LocTextKey PLEASE_SELECT_TEXT =
|
||||||
new LocTextKey("sebserver.overall.upload");
|
new LocTextKey("sebserver.overall.upload");
|
||||||
|
|
||||||
private final I18nSupport i18nSupport;
|
private final I18nSupport i18nSupport;
|
||||||
private final List<String> supportedFileExtensions = new ArrayList<>();
|
private final List<String> supportedFileExtensions = new ArrayList<>();
|
||||||
|
|
||||||
private final boolean readonly;
|
private final boolean readonly;
|
||||||
private final FileUpload fileUpload;
|
private final FileUpload fileUpload;
|
||||||
private final Label fileName;
|
private final Label fileName;
|
||||||
|
|
||||||
private Consumer<String> errorHandler;
|
private Consumer<String> errorHandler;
|
||||||
private InputStream inputStream;
|
private InputStream inputStream;
|
||||||
private final FileUploadHandler uploadHandler;
|
private final FileUploadHandler uploadHandler;
|
||||||
private final InputReceiver inputReceiver;
|
private final InputReceiver inputReceiver;
|
||||||
|
|
||||||
public FileUploadSelection(
|
public FileUploadSelection(
|
||||||
final Composite parent,
|
final Composite parent,
|
||||||
final I18nSupport i18nSupport,
|
final I18nSupport i18nSupport,
|
||||||
final boolean readonly) {
|
final boolean readonly) {
|
||||||
|
|
||||||
super(parent, SWT.NONE);
|
super(parent, SWT.NONE);
|
||||||
final GridLayout gridLayout = new GridLayout(2, false);
|
final GridLayout gridLayout = new GridLayout(2, false);
|
||||||
gridLayout.horizontalSpacing = 0;
|
gridLayout.horizontalSpacing = 0;
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.marginHeight = 0;
|
||||||
gridLayout.marginWidth = 0;
|
gridLayout.marginWidth = 0;
|
||||||
gridLayout.verticalSpacing = 0;
|
gridLayout.verticalSpacing = 0;
|
||||||
super.setLayout(gridLayout);
|
super.setLayout(gridLayout);
|
||||||
|
|
||||||
this.i18nSupport = i18nSupport;
|
this.i18nSupport = i18nSupport;
|
||||||
this.readonly = readonly;
|
this.readonly = readonly;
|
||||||
|
|
||||||
if (readonly) {
|
if (readonly) {
|
||||||
this.fileName = new Label(this, SWT.NONE);
|
this.fileName = new Label(this, SWT.NONE);
|
||||||
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
|
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
|
||||||
this.fileName.setLayoutData(new GridData());
|
this.fileName.setLayoutData(new GridData());
|
||||||
this.fileUpload = null;
|
this.fileUpload = null;
|
||||||
this.uploadHandler = null;
|
this.uploadHandler = null;
|
||||||
this.inputReceiver = null;
|
this.inputReceiver = null;
|
||||||
} else {
|
} else {
|
||||||
this.fileUpload = new FileUpload(this, SWT.NONE);
|
this.fileUpload = new FileUpload(this, SWT.NONE);
|
||||||
this.fileUpload.setImage(WidgetFactory.ImageIcon.IMPORT.getImage(parent.getDisplay()));
|
this.fileUpload.setImage(WidgetFactory.ImageIcon.IMPORT.getImage(parent.getDisplay()));
|
||||||
this.fileUpload.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
|
this.fileUpload.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
|
||||||
this.fileUpload.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(PLEASE_SELECT_TEXT)));
|
this.fileUpload.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(PLEASE_SELECT_TEXT)));
|
||||||
this.inputReceiver = new InputReceiver();
|
this.inputReceiver = new InputReceiver();
|
||||||
this.uploadHandler = new FileUploadHandler(this.inputReceiver);
|
this.uploadHandler = new FileUploadHandler(this.inputReceiver);
|
||||||
|
|
||||||
this.fileName = new Label(this, SWT.NONE);
|
this.fileName = new Label(this, SWT.NONE);
|
||||||
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
|
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
|
||||||
this.fileName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
|
this.fileName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
|
||||||
|
|
||||||
this.fileUpload.addListener(SWT.Selection, event -> {
|
this.fileUpload.addListener(SWT.Selection, event -> {
|
||||||
final String fileName = FileUploadSelection.this.fileUpload.getFileName();
|
final String fileName = FileUploadSelection.this.fileUpload.getFileName();
|
||||||
if (fileName == null || !fileSupported(fileName)) {
|
if (fileName == null || !fileSupported(fileName)) {
|
||||||
if (FileUploadSelection.this.errorHandler != null) {
|
if (FileUploadSelection.this.errorHandler != null) {
|
||||||
final String text = i18nSupport.getText(new LocTextKey(
|
final String text = i18nSupport.getText(new LocTextKey(
|
||||||
"sebserver.overall.upload.unsupported.file",
|
"sebserver.overall.upload.unsupported.file",
|
||||||
this.supportedFileExtensions.toString()),
|
this.supportedFileExtensions.toString()),
|
||||||
"Unsupported image file type selected");
|
"Unsupported image file type selected");
|
||||||
FileUploadSelection.this.errorHandler.accept(text);
|
FileUploadSelection.this.errorHandler.accept(text);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FileUploadSelection.this.fileUpload.submit(this.uploadHandler.getUploadUrl());
|
FileUploadSelection.this.fileUpload.submit(this.uploadHandler.getUploadUrl());
|
||||||
FileUploadSelection.this.fileName.setText(fileName);
|
FileUploadSelection.this.fileName.setText(fileName);
|
||||||
FileUploadSelection.this.errorHandler.accept(null);
|
FileUploadSelection.this.errorHandler.accept(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
if (this.inputReceiver != null) {
|
if (this.inputReceiver != null) {
|
||||||
this.inputReceiver.close();
|
this.inputReceiver.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (this.uploadHandler != null) {
|
if (this.uploadHandler != null) {
|
||||||
this.uploadHandler.dispose();
|
this.uploadHandler.dispose();
|
||||||
}
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
if (this.fileName != null) {
|
if (this.fileName != null) {
|
||||||
return this.fileName.getText();
|
return this.fileName.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Constants.EMPTY_NOTE;
|
return Constants.EMPTY_NOTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFileName(final String fileName) {
|
public void setFileName(final String fileName) {
|
||||||
if (this.fileName != null && fileName != null) {
|
if (this.fileName != null && fileName != null) {
|
||||||
this.fileName.setText(fileName);
|
this.fileName.setText(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
public InputStream getInputStream() {
|
||||||
return this.inputStream;
|
return this.inputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
if (this.inputStream != null) {
|
if (this.inputStream != null) {
|
||||||
this.fileName.setText(this.i18nSupport.getText(PLEASE_SELECT_TEXT));
|
this.fileName.setText(this.i18nSupport.getText(PLEASE_SELECT_TEXT));
|
||||||
}
|
}
|
||||||
if (!this.readonly) {
|
if (!this.readonly) {
|
||||||
this.fileUpload.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(PLEASE_SELECT_TEXT)));
|
this.fileUpload.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(PLEASE_SELECT_TEXT)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileUploadSelection setErrorHandler(final Consumer<String> errorHandler) {
|
public FileUploadSelection setErrorHandler(final Consumer<String> errorHandler) {
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileUploadSelection withSupportFor(final String fileExtension) {
|
public FileUploadSelection withSupportFor(final String fileExtension) {
|
||||||
this.supportedFileExtensions.add(fileExtension);
|
this.supportedFileExtensions.add(fileExtension);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean fileSupported(final String fileName) {
|
private boolean fileSupported(final String fileName) {
|
||||||
return this.supportedFileExtensions
|
return this.supportedFileExtensions
|
||||||
.stream()
|
.stream()
|
||||||
.filter(fileType -> fileName.toUpperCase(Locale.ROOT)
|
.anyMatch(fileType -> fileName.toUpperCase(Locale.ROOT)
|
||||||
.endsWith(fileType.toUpperCase(Locale.ROOT)))
|
.endsWith(fileType.toUpperCase(Locale.ROOT)));
|
||||||
.findFirst()
|
}
|
||||||
.isPresent();
|
|
||||||
}
|
private final class InputReceiver extends FileUploadReceiver {
|
||||||
|
private PipedInputStream pIn = null;
|
||||||
private final class InputReceiver extends FileUploadReceiver {
|
private PipedOutputStream pOut = null;
|
||||||
private PipedInputStream pIn = null;
|
|
||||||
private PipedOutputStream pOut = null;
|
@Override
|
||||||
|
public void receive(final InputStream stream, final FileDetails details) throws IOException {
|
||||||
@Override
|
if (this.pIn != null || this.pOut != null) {
|
||||||
public void receive(final InputStream stream, final FileDetails details) throws IOException {
|
throw new IllegalStateException("InputReceiver already in use");
|
||||||
if (this.pIn != null || this.pOut != null) {
|
}
|
||||||
throw new IllegalStateException("InputReceiver already in use");
|
|
||||||
}
|
this.pIn = new PipedInputStream();
|
||||||
|
this.pOut = new PipedOutputStream(this.pIn);
|
||||||
this.pIn = new PipedInputStream();
|
|
||||||
this.pOut = new PipedOutputStream(this.pIn);
|
FileUploadSelection.this.inputStream = this.pIn;
|
||||||
|
|
||||||
FileUploadSelection.this.inputStream = this.pIn;
|
try {
|
||||||
|
IOUtils.copyLarge(stream, this.pOut);
|
||||||
try {
|
} catch (final Exception e) {
|
||||||
IOUtils.copyLarge(stream, this.pOut);
|
log.warn("IO error: {}", e.getMessage());
|
||||||
} catch (final Exception e) {
|
} finally {
|
||||||
log.warn("IO error: {}", e.getMessage());
|
close();
|
||||||
} finally {
|
}
|
||||||
close();
|
}
|
||||||
}
|
|
||||||
}
|
void close() {
|
||||||
|
IOUtils.closeQuietly(this.pOut);
|
||||||
void close() {
|
}
|
||||||
IOUtils.closeQuietly(this.pOut);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,422 +1,421 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Button;
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Event;
|
import org.eclipse.swt.widgets.Event;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||||
|
|
||||||
public class GridTable extends Composite {
|
public class GridTable extends Composite {
|
||||||
|
|
||||||
private static final long serialVersionUID = 8515260041931976458L;
|
private static final long serialVersionUID = 8515260041931976458L;
|
||||||
private static final Logger log = LoggerFactory.getLogger(GridTable.class);
|
private static final Logger log = LoggerFactory.getLogger(GridTable.class);
|
||||||
|
|
||||||
public static final Set<AttributeType> SUPPORTED_TYPES = EnumSet.of(
|
public static final Set<AttributeType> SUPPORTED_TYPES = EnumSet.of(
|
||||||
AttributeType.CHECKBOX,
|
AttributeType.CHECKBOX,
|
||||||
AttributeType.TEXT_FIELD);
|
AttributeType.TEXT_FIELD);
|
||||||
|
|
||||||
private static final int ACTION_COLUMN_WIDTH = 20;
|
private static final int ACTION_COLUMN_WIDTH = 20;
|
||||||
|
|
||||||
private final WidgetFactory widgetFactory;
|
private final WidgetFactory widgetFactory;
|
||||||
private final List<Column> columns;
|
private final List<Column> columns;
|
||||||
private final Label addAction;
|
private final Label addAction;
|
||||||
private final List<Row> rows;
|
private final List<Row> rows;
|
||||||
private final String locTextKeyPrefix;
|
private final String locTextKeyPrefix;
|
||||||
private Listener listener;
|
private Listener listener;
|
||||||
|
|
||||||
public GridTable(
|
public GridTable(
|
||||||
final Composite parent,
|
final Composite parent,
|
||||||
final List<ColumnDef> columnDefs,
|
final List<ColumnDef> columnDefs,
|
||||||
final String locTextKeyPrefix,
|
final String locTextKeyPrefix,
|
||||||
final WidgetFactory widgetFactory) {
|
final WidgetFactory widgetFactory) {
|
||||||
|
|
||||||
super(parent, SWT.NONE);
|
super(parent, SWT.NONE);
|
||||||
|
|
||||||
this.widgetFactory = widgetFactory;
|
this.widgetFactory = widgetFactory;
|
||||||
this.locTextKeyPrefix = locTextKeyPrefix;
|
this.locTextKeyPrefix = locTextKeyPrefix;
|
||||||
final GridLayout gridLayout = new GridLayout(columnDefs.size() + 1, false);
|
final GridLayout gridLayout = new GridLayout(columnDefs.size() + 1, false);
|
||||||
gridLayout.verticalSpacing = 1;
|
gridLayout.verticalSpacing = 1;
|
||||||
gridLayout.marginLeft = 0;
|
gridLayout.marginLeft = 0;
|
||||||
gridLayout.marginHeight = 5;
|
gridLayout.marginHeight = 5;
|
||||||
gridLayout.marginWidth = 0;
|
gridLayout.marginWidth = 0;
|
||||||
gridLayout.horizontalSpacing = 0;
|
gridLayout.horizontalSpacing = 0;
|
||||||
this.setLayout(gridLayout);
|
this.setLayout(gridLayout);
|
||||||
|
|
||||||
this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||||
|
|
||||||
this.columns = new ArrayList<>();
|
this.columns = new ArrayList<>();
|
||||||
for (final ColumnDef columnDef : columnDefs) {
|
for (final ColumnDef columnDef : columnDefs) {
|
||||||
final Label label = widgetFactory.labelLocalized(
|
final Label label = widgetFactory.labelLocalized(
|
||||||
this,
|
this,
|
||||||
new LocTextKey(locTextKeyPrefix + columnDef.name));
|
new LocTextKey(locTextKeyPrefix + columnDef.name));
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
label.setLayoutData(gridData);
|
label.setLayoutData(gridData);
|
||||||
this.columns.add(new Column(columnDef, gridData));
|
this.columns.add(new Column(columnDef, gridData));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addAction = widgetFactory.imageButton(
|
this.addAction = widgetFactory.imageButton(
|
||||||
ImageIcon.ADD_BOX,
|
ImageIcon.ADD_BOX,
|
||||||
this,
|
this,
|
||||||
new LocTextKey(locTextKeyPrefix + "addAction"),
|
new LocTextKey(locTextKeyPrefix + "addAction"),
|
||||||
this::addRow);
|
this::addRow);
|
||||||
final GridData gridData = new GridData(SWT.CENTER, SWT.FILL, true, true);
|
final GridData gridData = new GridData(SWT.CENTER, SWT.FILL, true, true);
|
||||||
gridData.widthHint = ACTION_COLUMN_WIDTH;
|
gridData.widthHint = ACTION_COLUMN_WIDTH;
|
||||||
this.addAction.setLayoutData(gridData);
|
this.addAction.setLayoutData(gridData);
|
||||||
|
|
||||||
this.rows = new ArrayList<>();
|
this.rows = new ArrayList<>();
|
||||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setListener(final Listener listener) {
|
public void setListener(final Listener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRow(final Event event) {
|
void addRow(final Event event) {
|
||||||
final List<ControlAdapter> row = new ArrayList<>();
|
final List<ControlAdapter> row = new ArrayList<>();
|
||||||
for (final Column column : this.columns) {
|
for (final Column column : this.columns) {
|
||||||
row.add(createCell(column, column.columnDef.defaultValue));
|
row.add(createCell(column, column.columnDef.defaultValue));
|
||||||
}
|
}
|
||||||
this.rows.add(new Row(row));
|
this.rows.add(new Row(row));
|
||||||
|
|
||||||
this.adaptLayout();
|
this.adaptLayout();
|
||||||
|
|
||||||
if (this.listener != null) {
|
if (this.listener != null) {
|
||||||
this.listener.handleEvent(new Event());
|
this.listener.handleEvent(new Event());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void adaptLayout() {
|
public void adaptLayout() {
|
||||||
this.getParent().getParent().layout(true, true);
|
this.getParent().getParent().layout(true, true);
|
||||||
PageService.updateScrolledComposite(this);
|
PageService.updateScrolledComposite(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRow(final String values) {
|
void addRow(final String values) {
|
||||||
if (StringUtils.isBlank(values)) {
|
if (StringUtils.isBlank(values)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, String> nameValueMap = new HashMap<>();
|
final Map<String, String> nameValueMap = new HashMap<>();
|
||||||
for (final String valueMap : StringUtils.split(values, Constants.EMBEDDED_LIST_SEPARATOR)) {
|
for (final String valueMap : StringUtils.split(values, Constants.EMBEDDED_LIST_SEPARATOR)) {
|
||||||
final String[] nameValue = StringUtils.split(valueMap, Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR);
|
final String[] nameValue = StringUtils.split(valueMap, Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR);
|
||||||
if (nameValue.length > 1) {
|
if (nameValue.length > 1) {
|
||||||
nameValueMap.put(nameValue[0], nameValue[1]);
|
nameValueMap.put(nameValue[0], nameValue[1]);
|
||||||
} else {
|
} else {
|
||||||
nameValueMap.put(nameValue[0], null);
|
nameValueMap.put(nameValue[0], null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ControlAdapter> row = new ArrayList<>();
|
final List<ControlAdapter> row = new ArrayList<>();
|
||||||
for (final Column column : this.columns) {
|
for (final Column column : this.columns) {
|
||||||
row.add(createCell(column, nameValueMap.get(column.columnDef.name)));
|
row.add(createCell(column, nameValueMap.get(column.columnDef.name)));
|
||||||
}
|
}
|
||||||
this.rows.add(new Row(row));
|
this.rows.add(new Row(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteRow(final Row row) {
|
void deleteRow(final Row row) {
|
||||||
if (this.rows.remove(row)) {
|
if (this.rows.remove(row)) {
|
||||||
row.dispose();
|
row.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.adaptLayout();
|
this.adaptLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return StringUtils.join(
|
return StringUtils.join(
|
||||||
this.rows
|
this.rows
|
||||||
.stream()
|
.stream()
|
||||||
.map(row -> row.getValue())
|
.map(Row::getValue)
|
||||||
.collect(Collectors.toList()),
|
.collect(Collectors.toList()),
|
||||||
Constants.LIST_SEPARATOR);
|
Constants.LIST_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(final String value) {
|
public void setValue(final String value) {
|
||||||
clearTable();
|
clearTable();
|
||||||
|
|
||||||
if (StringUtils.isBlank(value)) {
|
if (StringUtils.isBlank(value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final String val : StringUtils.split(value, Constants.LIST_SEPARATOR)) {
|
for (final String val : StringUtils.split(value, Constants.LIST_SEPARATOR)) {
|
||||||
addRow(val);
|
addRow(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.adaptLayout();
|
this.adaptLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControlAdapter createCell(final Column column, final String value) {
|
private ControlAdapter createCell(final Column column, final String value) {
|
||||||
switch (column.columnDef.type) {
|
switch (column.columnDef.type) {
|
||||||
case CHECKBOX: {
|
case CHECKBOX: {
|
||||||
final CheckBox checkBox = new CheckBox(this, column.columnDef, this.listener);
|
final CheckBox checkBox = new CheckBox(this, column.columnDef, this.listener);
|
||||||
checkBox.setValue(value);
|
checkBox.setValue(value);
|
||||||
return checkBox;
|
return checkBox;
|
||||||
}
|
}
|
||||||
case TEXT_FIELD: {
|
case TEXT_FIELD: {
|
||||||
final TextField textField = new TextField(this, column.columnDef, this.listener);
|
final TextField textField = new TextField(this, column.columnDef, this.listener);
|
||||||
textField.setValue(value);
|
textField.setValue(value);
|
||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return new Dummy(this, column.columnDef);
|
return new Dummy(this, column.columnDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearTable() {
|
private void clearTable() {
|
||||||
for (final Row row : this.rows) {
|
for (final Row row : this.rows) {
|
||||||
row.dispose();
|
row.dispose();
|
||||||
}
|
}
|
||||||
this.rows.clear();
|
this.rows.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adaptColumnWidth(final Event event) {
|
private void adaptColumnWidth(final Event event) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
final int currentTableWidth = super.getClientArea().width - ACTION_COLUMN_WIDTH;
|
final int currentTableWidth = super.getClientArea().width - ACTION_COLUMN_WIDTH;
|
||||||
final int widthUnit = currentTableWidth / this.columns
|
final int widthUnit = currentTableWidth / this.columns
|
||||||
.stream()
|
.stream()
|
||||||
.reduce(0,
|
.reduce(0,
|
||||||
(i, c2) -> i + c2.columnDef.widthFactor,
|
(i, c2) -> i + c2.columnDef.widthFactor,
|
||||||
(i1, i2) -> i1 + i2);
|
Integer::sum);
|
||||||
|
|
||||||
this.columns
|
this.columns
|
||||||
.stream()
|
.forEach(c -> c.header.widthHint = c.columnDef.widthFactor * widthUnit);
|
||||||
.forEach(c -> c.header.widthHint = c.columnDef.widthFactor * widthUnit);
|
|
||||||
|
super.layout(true, true);
|
||||||
super.layout(true, true);
|
} catch (final Exception e) {
|
||||||
} catch (final Exception e) {
|
log.warn("Failed to adaptColumnWidth: ", e);
|
||||||
log.warn("Failed to adaptColumnWidth: ", e);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
final class Row {
|
||||||
final class Row {
|
final List<ControlAdapter> cells;
|
||||||
final List<ControlAdapter> cells;
|
final Label removeAction;
|
||||||
final Label removeAction;
|
|
||||||
|
protected Row(final List<ControlAdapter> cells) {
|
||||||
protected Row(final List<ControlAdapter> cells) {
|
this.cells = cells;
|
||||||
this.cells = cells;
|
this.removeAction = GridTable.this.widgetFactory.imageButton(
|
||||||
this.removeAction = GridTable.this.widgetFactory.imageButton(
|
ImageIcon.REMOVE_BOX,
|
||||||
ImageIcon.REMOVE_BOX,
|
GridTable.this,
|
||||||
GridTable.this,
|
new LocTextKey(GridTable.this.locTextKeyPrefix + "removeAction"),
|
||||||
new LocTextKey(GridTable.this.locTextKeyPrefix + "removeAction"),
|
event -> deleteRow(this));
|
||||||
event -> deleteRow(this));
|
final GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
|
||||||
final GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
|
gridData.widthHint = ACTION_COLUMN_WIDTH;
|
||||||
gridData.widthHint = ACTION_COLUMN_WIDTH;
|
this.removeAction.setLayoutData(gridData);
|
||||||
this.removeAction.setLayoutData(gridData);
|
}
|
||||||
}
|
|
||||||
|
void dispose() {
|
||||||
void dispose() {
|
for (final ControlAdapter cell : this.cells) {
|
||||||
for (final ControlAdapter cell : this.cells) {
|
cell.dispose();
|
||||||
cell.dispose();
|
}
|
||||||
}
|
this.removeAction.dispose();
|
||||||
this.removeAction.dispose();
|
}
|
||||||
}
|
|
||||||
|
String getValue() {
|
||||||
String getValue() {
|
return StringUtils.join(
|
||||||
return StringUtils.join(
|
this.cells
|
||||||
this.cells
|
.stream()
|
||||||
.stream()
|
.map(cell -> cell.columnDef().name + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR
|
||||||
.map(cell -> cell.columnDef().name + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR
|
+ cell.getValue())
|
||||||
+ cell.getValue())
|
.collect(Collectors.toList()),
|
||||||
.collect(Collectors.toList()),
|
Constants.EMBEDDED_LIST_SEPARATOR);
|
||||||
Constants.EMBEDDED_LIST_SEPARATOR);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static final class ColumnDef {
|
||||||
public static final class ColumnDef {
|
final int widthFactor;
|
||||||
final int widthFactor;
|
final String name;
|
||||||
final String name;
|
final AttributeType type;
|
||||||
final AttributeType type;
|
final String defaultValue;
|
||||||
final String defaultValue;
|
|
||||||
|
protected ColumnDef(
|
||||||
protected ColumnDef(
|
final int widthFactor,
|
||||||
final int widthFactor,
|
final String name,
|
||||||
final String name,
|
final AttributeType type,
|
||||||
final AttributeType type,
|
final String defaultValue) {
|
||||||
final String defaultValue) {
|
|
||||||
|
this.widthFactor = widthFactor;
|
||||||
this.widthFactor = widthFactor;
|
this.name = name;
|
||||||
this.name = name;
|
this.type = type;
|
||||||
this.type = type;
|
this.defaultValue = defaultValue;
|
||||||
this.defaultValue = defaultValue;
|
}
|
||||||
}
|
|
||||||
|
public static ColumnDef fromString(
|
||||||
public static final ColumnDef fromString(
|
final String string,
|
||||||
final String string,
|
final Map<String, String> defaultValueMap) {
|
||||||
final Map<String, String> defaultValueMap) {
|
|
||||||
|
if (StringUtils.isBlank(string)) {
|
||||||
if (StringUtils.isBlank(string)) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
final String[] split = StringUtils.split(string, Constants.COMPLEX_VALUE_SEPARATOR);
|
||||||
final String[] split = StringUtils.split(string, Constants.COMPLEX_VALUE_SEPARATOR);
|
final AttributeType attributeType = AttributeType.valueOf(split[2]);
|
||||||
final AttributeType attributeType = AttributeType.valueOf(split[2]);
|
if (!SUPPORTED_TYPES.contains(attributeType)) {
|
||||||
if (!SUPPORTED_TYPES.contains(attributeType)) {
|
throw new UnsupportedOperationException(
|
||||||
throw new UnsupportedOperationException(
|
"The AttributeType : " + attributeType + " is not supported yet");
|
||||||
"The AttributeType : " + attributeType + " is not supported yet");
|
}
|
||||||
}
|
|
||||||
|
return new ColumnDef(
|
||||||
return new ColumnDef(
|
Integer.parseInt(split[0]),
|
||||||
Integer.parseInt(split[0]),
|
split[1],
|
||||||
split[1],
|
attributeType,
|
||||||
attributeType,
|
defaultValueMap.get(split[1]));
|
||||||
defaultValueMap.get(split[1]));
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static class Column {
|
||||||
private static class Column {
|
final ColumnDef columnDef;
|
||||||
final ColumnDef columnDef;
|
final GridData header;
|
||||||
final GridData header;
|
|
||||||
|
protected Column(final ColumnDef columnDef, final GridData header) {
|
||||||
protected Column(final ColumnDef columnDef, final GridData header) {
|
this.columnDef = columnDef;
|
||||||
this.columnDef = columnDef;
|
this.header = header;
|
||||||
this.header = header;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
interface ControlAdapter {
|
||||||
interface ControlAdapter {
|
String getValue();
|
||||||
String getValue();
|
|
||||||
|
void setValue(String value);
|
||||||
void setValue(String value);
|
|
||||||
|
void dispose();
|
||||||
void dispose();
|
|
||||||
|
ColumnDef columnDef();
|
||||||
ColumnDef columnDef();
|
}
|
||||||
}
|
|
||||||
|
private static class Dummy implements ControlAdapter {
|
||||||
private static class Dummy implements ControlAdapter {
|
|
||||||
|
private final Label label;
|
||||||
private final Label label;
|
private final ColumnDef columnDef;
|
||||||
private final ColumnDef columnDef;
|
|
||||||
|
Dummy(final Composite parent, final ColumnDef columnDef) {
|
||||||
Dummy(final Composite parent, final ColumnDef columnDef) {
|
this.label = new Label(parent, SWT.NONE);
|
||||||
this.label = new Label(parent, SWT.NONE);
|
this.label.setText("unsupported");
|
||||||
this.label.setText("unsupported");
|
this.columnDef = columnDef;
|
||||||
this.columnDef = columnDef;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public String getValue() {
|
||||||
public String getValue() {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void setValue(final String value) {
|
||||||
public void setValue(final String value) {
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void dispose() {
|
||||||
public void dispose() {
|
this.label.dispose();
|
||||||
this.label.dispose();
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public ColumnDef columnDef() {
|
||||||
public ColumnDef columnDef() {
|
return this.columnDef;
|
||||||
return this.columnDef;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static class CheckBox implements ControlAdapter {
|
||||||
private static class CheckBox implements ControlAdapter {
|
|
||||||
|
private final Button checkboxButton;
|
||||||
private final Button checkboxButton;
|
private final ColumnDef columnDef;
|
||||||
private final ColumnDef columnDef;
|
|
||||||
|
CheckBox(final Composite parent, final ColumnDef columnDef, final Listener listener) {
|
||||||
CheckBox(final Composite parent, final ColumnDef columnDef, final Listener listener) {
|
this.checkboxButton = new Button(parent, SWT.CHECK);
|
||||||
this.checkboxButton = new Button(parent, SWT.CHECK);
|
this.checkboxButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||||
this.checkboxButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
this.columnDef = columnDef;
|
||||||
this.columnDef = columnDef;
|
if (listener != null) {
|
||||||
if (listener != null) {
|
this.checkboxButton.addListener(SWT.Selection, listener);
|
||||||
this.checkboxButton.addListener(SWT.Selection, listener);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public String getValue() {
|
||||||
public String getValue() {
|
return this.checkboxButton.getSelection()
|
||||||
return this.checkboxButton.getSelection()
|
? Constants.TRUE_STRING
|
||||||
? Constants.TRUE_STRING
|
: Constants.FALSE_STRING;
|
||||||
: Constants.FALSE_STRING;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void setValue(final String value) {
|
||||||
public void setValue(final String value) {
|
this.checkboxButton.setSelection(BooleanUtils.toBoolean(value));
|
||||||
this.checkboxButton.setSelection(BooleanUtils.toBoolean(value));
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void dispose() {
|
||||||
public void dispose() {
|
this.checkboxButton.dispose();
|
||||||
this.checkboxButton.dispose();
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public ColumnDef columnDef() {
|
||||||
public ColumnDef columnDef() {
|
return this.columnDef;
|
||||||
return this.columnDef;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static class TextField implements ControlAdapter {
|
||||||
private static class TextField implements ControlAdapter {
|
|
||||||
|
private final Text _textField;
|
||||||
private final Text _textField;
|
private final ColumnDef columnDef;
|
||||||
private final ColumnDef columnDef;
|
|
||||||
|
TextField(final Composite parent, final ColumnDef columnDef, final Listener listener) {
|
||||||
TextField(final Composite parent, final ColumnDef columnDef, final Listener listener) {
|
this._textField = new Text(parent, SWT.LEFT | SWT.BORDER);
|
||||||
this._textField = new Text(parent, SWT.LEFT | SWT.BORDER);
|
this._textField.setData(RWT.CUSTOM_VARIANT, CustomVariant.CONFIG_INPUT_READONLY.key);
|
||||||
this._textField.setData(RWT.CUSTOM_VARIANT, CustomVariant.CONFIG_INPUT_READONLY.key);
|
this._textField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||||
this._textField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
this.columnDef = columnDef;
|
||||||
this.columnDef = columnDef;
|
this._textField.addListener(SWT.FocusOut, listener);
|
||||||
this._textField.addListener(SWT.FocusOut, listener);
|
this._textField.addListener(SWT.Traverse, listener);
|
||||||
this._textField.addListener(SWT.Traverse, listener);
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public String getValue() {
|
||||||
public String getValue() {
|
return this._textField.getText();
|
||||||
return this._textField.getText();
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void setValue(final String value) {
|
||||||
public void setValue(final String value) {
|
this._textField.setText((value != null) ? value : "");
|
||||||
this._textField.setText((value != null) ? value : "");
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void dispose() {
|
||||||
public void dispose() {
|
this._textField.dispose();
|
||||||
this._textField.dispose();
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public ColumnDef columnDef() {
|
||||||
public ColumnDef columnDef() {
|
return this.columnDef;
|
||||||
return this.columnDef;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,222 +1,213 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64InputStream;
|
import org.apache.commons.codec.binary.Base64InputStream;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.rap.fileupload.FileDetails;
|
import org.eclipse.rap.fileupload.FileDetails;
|
||||||
import org.eclipse.rap.fileupload.FileUploadHandler;
|
import org.eclipse.rap.fileupload.FileUploadHandler;
|
||||||
import org.eclipse.rap.fileupload.FileUploadReceiver;
|
import org.eclipse.rap.fileupload.FileUploadReceiver;
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.rap.rwt.widgets.FileUpload;
|
import org.eclipse.rap.rwt.widgets.FileUpload;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.graphics.Image;
|
import org.eclipse.swt.graphics.Image;
|
||||||
import org.eclipse.swt.graphics.ImageData;
|
import org.eclipse.swt.graphics.ImageData;
|
||||||
import org.eclipse.swt.graphics.Rectangle;
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.push.ServerPushContext;
|
import ch.ethz.seb.sebserver.gui.service.push.ServerPushContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
|
import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
|
||||||
|
|
||||||
public final class ImageUploadSelection extends Composite {
|
public final class ImageUploadSelection extends Composite {
|
||||||
|
|
||||||
private static final long serialVersionUID = 368264811155804533L;
|
private static final long serialVersionUID = 368264811155804533L;
|
||||||
private static final Logger log = LoggerFactory.getLogger(ImageUploadSelection.class);
|
private static final Logger log = LoggerFactory.getLogger(ImageUploadSelection.class);
|
||||||
|
|
||||||
public static final Set<String> SUPPORTED_IMAGE_FILES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
|
public static final Set<String> SUPPORTED_IMAGE_FILES = Set.of(".png", ".jpg", ".jpeg");
|
||||||
".png",
|
|
||||||
".jpg",
|
private final ServerPushService serverPushService;
|
||||||
".jpeg")));
|
|
||||||
|
private final Composite imageCanvas;
|
||||||
private final ServerPushService serverPushService;
|
private final FileUpload fileUpload;
|
||||||
|
private final int maxWidth;
|
||||||
private final Composite imageCanvas;
|
private final int maxHeight;
|
||||||
private final FileUpload fileUpload;
|
|
||||||
private final int maxWidth;
|
private Consumer<String> errorHandler;
|
||||||
private final int maxHeight;
|
private String imageBase64 = null;
|
||||||
|
private boolean loadNewImage = false;
|
||||||
private Consumer<String> errorHandler;
|
private boolean imageLoaded = false;
|
||||||
private String imageBase64 = null;
|
|
||||||
private boolean loadNewImage = false;
|
ImageUploadSelection(
|
||||||
private boolean imageLoaded = false;
|
final Composite parent,
|
||||||
|
final ServerPushService serverPushService,
|
||||||
ImageUploadSelection(
|
final I18nSupport i18nSupport,
|
||||||
final Composite parent,
|
final boolean readonly,
|
||||||
final ServerPushService serverPushService,
|
final int maxWidth,
|
||||||
final I18nSupport i18nSupport,
|
final int maxHeight) {
|
||||||
final boolean readonly,
|
|
||||||
final int maxWidth,
|
super(parent, SWT.NONE);
|
||||||
final int maxHeight) {
|
final GridLayout gridLayout = new GridLayout(1, false);
|
||||||
|
gridLayout.horizontalSpacing = 0;
|
||||||
super(parent, SWT.NONE);
|
gridLayout.marginHeight = 0;
|
||||||
final GridLayout gridLayout = new GridLayout(1, false);
|
gridLayout.marginWidth = 0;
|
||||||
gridLayout.horizontalSpacing = 0;
|
gridLayout.marginLeft = 0;
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.verticalSpacing = 0;
|
||||||
gridLayout.marginWidth = 0;
|
super.setLayout(gridLayout);
|
||||||
gridLayout.marginLeft = 0;
|
|
||||||
gridLayout.verticalSpacing = 0;
|
this.serverPushService = serverPushService;
|
||||||
super.setLayout(gridLayout);
|
this.maxWidth = maxWidth;
|
||||||
|
this.maxHeight = maxHeight;
|
||||||
this.serverPushService = serverPushService;
|
|
||||||
this.maxWidth = maxWidth;
|
if (!readonly) {
|
||||||
this.maxHeight = maxHeight;
|
this.fileUpload = new FileUpload(this, SWT.NONE);
|
||||||
|
this.fileUpload.setImage(WidgetFactory.ImageIcon.IMPORT.getImage(parent.getDisplay()));
|
||||||
if (!readonly) {
|
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||||
this.fileUpload = new FileUpload(this, SWT.NONE);
|
gridData.horizontalIndent = 0;
|
||||||
this.fileUpload.setImage(WidgetFactory.ImageIcon.IMPORT.getImage(parent.getDisplay()));
|
this.fileUpload.setLayoutData(gridData);
|
||||||
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
|
||||||
gridData.horizontalIndent = 0;
|
final FileUploadHandler uploadHandler = new FileUploadHandler(new ImageReceiver());
|
||||||
this.fileUpload.setLayoutData(gridData);
|
this.fileUpload.addListener(SWT.Selection, event -> {
|
||||||
|
final String fileName = ImageUploadSelection.this.fileUpload.getFileName();
|
||||||
final FileUploadHandler uploadHandler = new FileUploadHandler(new ImageReceiver());
|
if (fileName == null || !fileSupported(fileName)) {
|
||||||
this.fileUpload.addListener(SWT.Selection, event -> {
|
if (ImageUploadSelection.this.errorHandler != null) {
|
||||||
final String fileName = ImageUploadSelection.this.fileUpload.getFileName();
|
final String text = i18nSupport.getText(
|
||||||
if (fileName == null || !fileSupported(fileName)) {
|
"sebserver.institution.form.logoImage.unsupportedFileType",
|
||||||
if (ImageUploadSelection.this.errorHandler != null) {
|
"Unsupported image file type selected");
|
||||||
final String text = i18nSupport.getText(
|
ImageUploadSelection.this.errorHandler.accept(text);
|
||||||
"sebserver.institution.form.logoImage.unsupportedFileType",
|
}
|
||||||
"Unsupported image file type selected");
|
|
||||||
ImageUploadSelection.this.errorHandler.accept(text);
|
log.warn("Unsupported image file selected: {}", fileName);
|
||||||
}
|
|
||||||
|
return;
|
||||||
log.warn("Unsupported image file selected: {}", fileName);
|
}
|
||||||
|
ImageUploadSelection.this.loadNewImage = true;
|
||||||
return;
|
ImageUploadSelection.this.imageLoaded = false;
|
||||||
}
|
ImageUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl());
|
||||||
ImageUploadSelection.this.loadNewImage = true;
|
|
||||||
ImageUploadSelection.this.imageLoaded = false;
|
ImageUploadSelection.this.serverPushService.runServerPush(
|
||||||
ImageUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl());
|
new ServerPushContext(ImageUploadSelection.this, ImageUploadSelection::uploadInProgress),
|
||||||
|
200,
|
||||||
ImageUploadSelection.this.serverPushService.runServerPush(
|
ImageUploadSelection::update);
|
||||||
new ServerPushContext(ImageUploadSelection.this, ImageUploadSelection::uploadInProgress),
|
});
|
||||||
200,
|
} else {
|
||||||
ImageUploadSelection::update);
|
this.fileUpload = null;
|
||||||
});
|
}
|
||||||
} else {
|
|
||||||
this.fileUpload = null;
|
this.imageCanvas = new Composite(this, SWT.NONE);
|
||||||
}
|
final GridData canvas = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||||
|
this.imageCanvas.setLayoutData(canvas);
|
||||||
this.imageCanvas = new Composite(this, SWT.NONE);
|
}
|
||||||
final GridData canvas = new GridData(SWT.FILL, SWT.FILL, true, true);
|
|
||||||
this.imageCanvas.setLayoutData(canvas);
|
public void setErrorHandler(final Consumer<String> errorHandler) {
|
||||||
}
|
this.errorHandler = errorHandler;
|
||||||
|
}
|
||||||
public void setErrorHandler(final Consumer<String> errorHandler) {
|
|
||||||
this.errorHandler = errorHandler;
|
public void setSelectionText(final String text) {
|
||||||
}
|
if (this.fileUpload != null) {
|
||||||
|
this.fileUpload.setToolTipText(Utils.formatLineBreaks(text));
|
||||||
public void setSelectionText(final String text) {
|
}
|
||||||
if (this.fileUpload != null) {
|
}
|
||||||
this.fileUpload.setToolTipText(Utils.formatLineBreaks(text));
|
|
||||||
}
|
public String getImageBase64() {
|
||||||
}
|
return this.imageBase64;
|
||||||
|
}
|
||||||
public String getImageBase64() {
|
|
||||||
return this.imageBase64;
|
public void setImageBase64(final String imageBase64) {
|
||||||
}
|
if (StringUtils.isBlank(imageBase64)) {
|
||||||
|
return;
|
||||||
public void setImageBase64(final String imageBase64) {
|
}
|
||||||
if (StringUtils.isBlank(imageBase64)) {
|
|
||||||
return;
|
this.imageBase64 = imageBase64;
|
||||||
}
|
final Base64InputStream input = new Base64InputStream(
|
||||||
|
new ByteArrayInputStream(imageBase64.getBytes(StandardCharsets.UTF_8)), false);
|
||||||
this.imageBase64 = imageBase64;
|
|
||||||
final Base64InputStream input = new Base64InputStream(
|
setImage(this, input);
|
||||||
new ByteArrayInputStream(imageBase64.getBytes(StandardCharsets.UTF_8)), false);
|
}
|
||||||
|
|
||||||
setImage(this, input);
|
private static boolean uploadInProgress(final ServerPushContext context) {
|
||||||
}
|
final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor();
|
||||||
|
return imageUpload.loadNewImage && !imageUpload.imageLoaded;
|
||||||
private static final boolean uploadInProgress(final ServerPushContext context) {
|
}
|
||||||
final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor();
|
|
||||||
return imageUpload.loadNewImage && !imageUpload.imageLoaded;
|
private static void update(final ServerPushContext context) {
|
||||||
}
|
final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor();
|
||||||
|
if (imageUpload.imageBase64 != null
|
||||||
private static final void update(final ServerPushContext context) {
|
&& imageUpload.loadNewImage
|
||||||
final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor();
|
&& imageUpload.imageLoaded) {
|
||||||
if (imageUpload.imageBase64 != null
|
|
||||||
&& imageUpload.loadNewImage
|
final Base64InputStream input = new Base64InputStream(
|
||||||
&& imageUpload.imageLoaded) {
|
new ByteArrayInputStream(
|
||||||
|
imageUpload.imageBase64.getBytes(StandardCharsets.UTF_8)),
|
||||||
final Base64InputStream input = new Base64InputStream(
|
false);
|
||||||
new ByteArrayInputStream(
|
|
||||||
imageUpload.imageBase64.getBytes(StandardCharsets.UTF_8)),
|
setImage(imageUpload, input);
|
||||||
false);
|
context.layout();
|
||||||
|
imageUpload.layout();
|
||||||
setImage(imageUpload, input);
|
imageUpload.loadNewImage = false;
|
||||||
context.layout();
|
imageUpload.errorHandler.accept(null);
|
||||||
imageUpload.layout();
|
}
|
||||||
imageUpload.loadNewImage = false;
|
}
|
||||||
imageUpload.errorHandler.accept(null);
|
|
||||||
}
|
private static void setImage(final ImageUploadSelection imageUpload, final Base64InputStream input) {
|
||||||
}
|
imageUpload.imageCanvas.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");
|
||||||
|
|
||||||
private static void setImage(final ImageUploadSelection imageUpload, final Base64InputStream input) {
|
final Image image = new Image(imageUpload.imageCanvas.getDisplay(), input);
|
||||||
imageUpload.imageCanvas.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");
|
final Rectangle imageBounds = image.getBounds();
|
||||||
|
final int width = Math.min(imageBounds.width, imageUpload.maxWidth);
|
||||||
final Image image = new Image(imageUpload.imageCanvas.getDisplay(), input);
|
final int height = Math.min(imageBounds.height, imageUpload.maxHeight);
|
||||||
final Rectangle imageBounds = image.getBounds();
|
final ImageData imageData = image.getImageData().scaledTo(width, height);
|
||||||
final int width = (imageBounds.width > imageUpload.maxWidth)
|
imageUpload.imageCanvas.setBackgroundImage(new Image(imageUpload.imageCanvas.getDisplay(), imageData));
|
||||||
? imageUpload.maxWidth
|
}
|
||||||
: imageBounds.width;
|
|
||||||
final int height = (imageBounds.height > imageUpload.maxHeight)
|
private static boolean fileSupported(final String fileName) {
|
||||||
? imageUpload.maxHeight
|
return SUPPORTED_IMAGE_FILES
|
||||||
: imageBounds.height;
|
.stream()
|
||||||
final ImageData imageData = image.getImageData().scaledTo(width, height);
|
.anyMatch(fileType -> fileName.toUpperCase(Locale.ROOT)
|
||||||
imageUpload.imageCanvas.setBackgroundImage(new Image(imageUpload.imageCanvas.getDisplay(), imageData));
|
.endsWith(fileType.toUpperCase(Locale.ROOT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean fileSupported(final String fileName) {
|
private final class ImageReceiver extends FileUploadReceiver {
|
||||||
return SUPPORTED_IMAGE_FILES
|
@Override
|
||||||
.stream()
|
public void receive(final InputStream stream, final FileDetails details) throws IOException {
|
||||||
.filter(fileType -> fileName.toUpperCase(Locale.ROOT)
|
|
||||||
.endsWith(fileType.toUpperCase(Locale.ROOT)))
|
try {
|
||||||
.findFirst()
|
final String contentType = details.getContentType();
|
||||||
.isPresent();
|
if (contentType != null && contentType.startsWith("image")) {
|
||||||
}
|
ImageUploadSelection.this.imageBase64 = Base64.getEncoder()
|
||||||
|
.encodeToString(IOUtils.toByteArray(stream));
|
||||||
private final class ImageReceiver extends FileUploadReceiver {
|
}
|
||||||
@Override
|
} catch (final Exception e) {
|
||||||
public void receive(final InputStream stream, final FileDetails details) throws IOException {
|
log.error("Error while trying to upload image", e);
|
||||||
|
} finally {
|
||||||
try {
|
ImageUploadSelection.this.imageLoaded = true;
|
||||||
final String contentType = details.getContentType();
|
stream.close();
|
||||||
if (contentType != null && contentType.startsWith("image")) {
|
}
|
||||||
ImageUploadSelection.this.imageBase64 = Base64.getEncoder()
|
}
|
||||||
.encodeToString(IOUtils.toByteArray(stream));
|
}
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
}
|
||||||
log.error("Error while trying to upload image", e);
|
|
||||||
} finally {
|
|
||||||
ImageUploadSelection.this.imageLoaded = true;
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,12 +8,11 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import java.util.LinkedHashMap;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import java.util.List;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple3;
|
||||||
import java.util.Map;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import java.util.stream.Collectors;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
@ -22,11 +21,10 @@ import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import java.util.Arrays;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
import java.util.LinkedHashMap;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple3;
|
import java.util.List;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import java.util.Map;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
|
||||||
|
|
||||||
public final class MultiSelectionCheckbox extends Composite implements Selection {
|
public final class MultiSelectionCheckbox extends Composite implements Selection {
|
||||||
|
|
||||||
|
@ -121,7 +119,7 @@ public final class MultiSelectionCheckbox extends Composite implements Selection
|
||||||
.stream()
|
.stream()
|
||||||
.filter(Button::getSelection)
|
.filter(Button::getSelection)
|
||||||
.map(button -> (String) button.getData(OPTION_VALUE))
|
.map(button -> (String) button.getData(OPTION_VALUE))
|
||||||
.collect(Collectors.toList()).toArray());
|
.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,252 +1,230 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import java.util.Arrays;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import java.util.Collection;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import java.util.List;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import java.util.Optional;
|
import org.eclipse.rap.rwt.widgets.DropDown;
|
||||||
import java.util.stream.Collectors;
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.rap.rwt.widgets.DropDown;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.widgets.Control;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.widgets.Event;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
import org.eclipse.swt.widgets.Control;
|
import org.eclipse.swt.widgets.Text;
|
||||||
import org.eclipse.swt.widgets.Event;
|
import org.slf4j.Logger;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
|
||||||
import org.eclipse.swt.widgets.Text;
|
import java.util.ArrayList;
|
||||||
import org.slf4j.Logger;
|
import java.util.Arrays;
|
||||||
import org.slf4j.LoggerFactory;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MultiSelectionCombo.class);
|
||||||
public final class MultiSelectionCombo extends Composite implements Selection {
|
private static final long serialVersionUID = -7787134114963647332L;
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MultiSelectionCombo.class);
|
private final WidgetFactory widgetFactory;
|
||||||
private static final long serialVersionUID = -7787134114963647332L;
|
|
||||||
|
private final List<Control> selectionControls = new ArrayList<>();
|
||||||
private final WidgetFactory widgetFactory;
|
|
||||||
|
private final List<Tuple<String>> valueMapping = new ArrayList<>();
|
||||||
private final List<Control> selectionControls = new ArrayList<>();
|
private final List<Tuple<String>> availableValues = new ArrayList<>();
|
||||||
|
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
||||||
private final List<Tuple<String>> valueMapping = new ArrayList<>();
|
|
||||||
private final List<Tuple<String>> availableValues = new ArrayList<>();
|
private final DropDown dropDown;
|
||||||
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
private final Text textInput;
|
||||||
|
private final GridData textCell;
|
||||||
private final DropDown dropDown;
|
private final Composite updateAnchor;
|
||||||
private final Text textInput;
|
|
||||||
private final GridData textCell;
|
private Listener listener = null;
|
||||||
private final Composite updateAnchor;
|
|
||||||
|
MultiSelectionCombo(
|
||||||
private Listener listener = null;
|
final Composite parent,
|
||||||
|
final WidgetFactory widgetFactory,
|
||||||
MultiSelectionCombo(
|
final String locTextPrefix,
|
||||||
final Composite parent,
|
final Composite updateAnchor) {
|
||||||
final WidgetFactory widgetFactory,
|
|
||||||
final String locTextPrefix,
|
super(parent, SWT.NONE);
|
||||||
final Composite updateAnchor) {
|
this.widgetFactory = widgetFactory;
|
||||||
|
|
||||||
super(parent, SWT.NONE);
|
final GridLayout gridLayout = new GridLayout();
|
||||||
this.widgetFactory = widgetFactory;
|
gridLayout.verticalSpacing = 1;
|
||||||
|
gridLayout.marginLeft = 0;
|
||||||
final GridLayout gridLayout = new GridLayout();
|
gridLayout.marginHeight = 0;
|
||||||
gridLayout.verticalSpacing = 1;
|
gridLayout.marginWidth = 0;
|
||||||
gridLayout.marginLeft = 0;
|
gridLayout.horizontalSpacing = 0;
|
||||||
gridLayout.marginHeight = 0;
|
setLayout(gridLayout);
|
||||||
gridLayout.marginWidth = 0;
|
|
||||||
gridLayout.horizontalSpacing = 0;
|
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||||
setLayout(gridLayout);
|
this.textInput = widgetFactory.textInput(this);
|
||||||
|
this.textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
||||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
this.textInput.setLayoutData(this.textCell);
|
||||||
this.textInput = widgetFactory.textInput(this);
|
this.dropDown = new DropDown(this.textInput, SWT.NONE);
|
||||||
this.textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
this.textInput.addListener(SWT.FocusIn, event -> openDropDown());
|
||||||
this.textInput.setLayoutData(this.textCell);
|
this.textInput.addListener(SWT.Modify, event -> openDropDown());
|
||||||
this.dropDown = new DropDown(this.textInput, SWT.NONE);
|
this.dropDown.addListener(SWT.Selection, event -> {
|
||||||
this.textInput.addListener(SWT.FocusIn, event -> {
|
final int selectionIndex = this.dropDown.getSelectionIndex();
|
||||||
openDropDown();
|
if (selectionIndex >= 0) {
|
||||||
});
|
final String selectedItem = this.dropDown.getItems()[selectionIndex];
|
||||||
this.textInput.addListener(SWT.Modify, event -> {
|
addSelection(itemForName(selectedItem));
|
||||||
openDropDown();
|
}
|
||||||
});
|
});
|
||||||
this.dropDown.addListener(SWT.Selection, event -> {
|
|
||||||
final int selectionIndex = this.dropDown.getSelectionIndex();
|
this.updateAnchor = updateAnchor;
|
||||||
if (selectionIndex >= 0) {
|
}
|
||||||
final String selectedItem = this.dropDown.getItems()[selectionIndex];
|
|
||||||
addSelection(itemForName(selectedItem));
|
private void openDropDown() {
|
||||||
}
|
final String text = this.textInput.getText();
|
||||||
});
|
if (text == null) {
|
||||||
|
this.dropDown.setVisible(false);
|
||||||
this.updateAnchor = updateAnchor;
|
return;
|
||||||
}
|
}
|
||||||
|
this.dropDown.setItems(this.availableValues
|
||||||
private void openDropDown() {
|
.stream()
|
||||||
final String text = this.textInput.getText();
|
.filter(it -> it._2 != null && it._2.startsWith(text))
|
||||||
if (text == null) {
|
.map(t -> t._2).toArray(String[]::new));
|
||||||
this.dropDown.setVisible(false);
|
this.dropDown.setSelectionIndex(0);
|
||||||
return;
|
this.dropDown.setVisible(true);
|
||||||
}
|
}
|
||||||
final Collection<String> items = this.availableValues
|
|
||||||
.stream()
|
@Override
|
||||||
.filter(it -> it._2 != null && it._2.startsWith(text))
|
public Type type() {
|
||||||
.map(t -> t._2)
|
return Type.MULTI_COMBO;
|
||||||
.collect(Collectors.toList());
|
}
|
||||||
this.dropDown.setItems(items.toArray(new String[items.size()]));
|
|
||||||
this.dropDown.setSelectionIndex(0);
|
@Override
|
||||||
this.dropDown.setVisible(true);
|
public void setSelectionListener(final Listener listener) {
|
||||||
}
|
this.listener = listener;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public Type type() {
|
@Override
|
||||||
return Type.MULTI_COMBO;
|
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
||||||
}
|
this.valueMapping.clear();
|
||||||
|
this.valueMapping.addAll(mapping);
|
||||||
@Override
|
this.clear();
|
||||||
public void setSelectionListener(final Listener listener) {
|
}
|
||||||
this.listener = listener;
|
|
||||||
}
|
@Override
|
||||||
|
public void select(final String keys) {
|
||||||
@Override
|
clear();
|
||||||
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
if (StringUtils.isBlank(keys)) {
|
||||||
this.valueMapping.clear();
|
return;
|
||||||
this.valueMapping.addAll(mapping);
|
}
|
||||||
this.clear();
|
|
||||||
}
|
Arrays.stream(StringUtils.split(keys, Constants.LIST_SEPARATOR))
|
||||||
|
.map(this::itemForId)
|
||||||
@Override
|
.forEach(this::addSelection);
|
||||||
public void select(final String keys) {
|
}
|
||||||
clear();
|
|
||||||
if (StringUtils.isBlank(keys)) {
|
@Override
|
||||||
return;
|
public String getSelectionValue() {
|
||||||
}
|
if (this.selectedValues.isEmpty()) {
|
||||||
|
return null;
|
||||||
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR))
|
}
|
||||||
.stream()
|
return this.selectedValues
|
||||||
.map(this::itemForId)
|
.stream()
|
||||||
.forEach(this::addSelection);
|
.map(t -> t._1)
|
||||||
}
|
.reduce("", (s1, s2) -> {
|
||||||
|
if (!StringUtils.isBlank(s1)) {
|
||||||
@Override
|
return s1.concat(Constants.LIST_SEPARATOR).concat(s2);
|
||||||
public String getSelectionValue() {
|
} else {
|
||||||
if (this.selectedValues.isEmpty()) {
|
return s1.concat(s2);
|
||||||
return null;
|
}
|
||||||
}
|
});
|
||||||
return this.selectedValues
|
}
|
||||||
.stream()
|
|
||||||
.map(t -> t._1)
|
@Override
|
||||||
.reduce("", (s1, s2) -> {
|
public void clear() {
|
||||||
if (!StringUtils.isBlank(s1)) {
|
this.selectedValues.clear();
|
||||||
return s1.concat(Constants.LIST_SEPARATOR).concat(s2);
|
this.selectionControls
|
||||||
} else {
|
.forEach(Control::dispose);
|
||||||
return s1.concat(s2);
|
this.selectionControls.clear();
|
||||||
}
|
this.availableValues.clear();
|
||||||
});
|
this.availableValues.addAll(this.valueMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void addSelection(final Tuple<String> item) {
|
||||||
public void clear() {
|
if (item == null) {
|
||||||
this.selectedValues.clear();
|
return;
|
||||||
this.selectionControls
|
}
|
||||||
.stream()
|
|
||||||
.forEach(Control::dispose);
|
this.selectedValues.add(item);
|
||||||
this.selectionControls.clear();
|
final Label label = this.widgetFactory.label(this, item._2);
|
||||||
this.availableValues.clear();
|
label.setData(OPTION_VALUE, item._2);
|
||||||
this.availableValues.addAll(this.valueMapping);
|
final GridData textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
||||||
}
|
label.setLayoutData(textCell);
|
||||||
|
label.addListener(SWT.MouseDoubleClick, this::removeComboSelection);
|
||||||
private void addSelection(final Tuple<String> item) {
|
this.selectionControls.add(label);
|
||||||
if (item == null) {
|
|
||||||
return;
|
this.availableValues.remove(item);
|
||||||
}
|
PageService.updateScrolledComposite(this);
|
||||||
|
this.updateAnchor.layout(true, true);
|
||||||
this.selectedValues.add(item);
|
|
||||||
final Label label = this.widgetFactory.label(this, item._2);
|
}
|
||||||
label.setData(OPTION_VALUE, item._2);
|
|
||||||
final GridData textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
private void removeComboSelection(final Event event) {
|
||||||
label.setLayoutData(textCell);
|
if (event.widget == null) {
|
||||||
label.addListener(SWT.MouseDoubleClick, event -> {
|
return;
|
||||||
removeComboSelection(event);
|
}
|
||||||
});
|
|
||||||
this.selectionControls.add(label);
|
final String selectionKey = (String) event.widget.getData(OPTION_VALUE);
|
||||||
|
final Optional<Control> findFirst = this.selectionControls.stream()
|
||||||
this.availableValues.remove(item);
|
.filter(t -> selectionKey.equals(t.getData(OPTION_VALUE)))
|
||||||
PageService.updateScrolledComposite(this);
|
.findFirst();
|
||||||
this.updateAnchor.layout(true, true);
|
if (!findFirst.isPresent()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeComboSelection(final Event event) {
|
final Control control = findFirst.get();
|
||||||
if (event.widget == null) {
|
final int indexOf = this.selectionControls.indexOf(control);
|
||||||
return;
|
this.selectionControls.remove(control);
|
||||||
}
|
control.dispose();
|
||||||
|
|
||||||
final String selectionKey = (String) event.widget.getData(OPTION_VALUE);
|
final Tuple<String> value = this.selectedValues.remove(indexOf);
|
||||||
final Optional<Control> findFirst = this.selectionControls.stream()
|
this.availableValues.add(value);
|
||||||
.filter(t -> selectionKey.equals(t.getData(OPTION_VALUE)))
|
|
||||||
.findFirst();
|
PageService.updateScrolledComposite(this);
|
||||||
if (!findFirst.isPresent()) {
|
this.updateAnchor.layout(true, true);
|
||||||
return;
|
if (this.listener != null) {
|
||||||
}
|
this.listener.handleEvent(event);
|
||||||
|
}
|
||||||
final Control control = findFirst.get();
|
}
|
||||||
final int indexOf = this.selectionControls.indexOf(control);
|
|
||||||
this.selectionControls.remove(control);
|
private void adaptColumnWidth(final Event event) {
|
||||||
control.dispose();
|
try {
|
||||||
|
this.textCell.widthHint = this.getClientArea().width;
|
||||||
final Tuple<String> value = this.selectedValues.remove(indexOf);
|
this.layout();
|
||||||
this.availableValues.add(value);
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to adaptColumnWidth: ", e);
|
||||||
PageService.updateScrolledComposite(this);
|
}
|
||||||
this.updateAnchor.layout(true, true);
|
}
|
||||||
if (this.listener != null) {
|
|
||||||
this.listener.handleEvent(event);
|
private Tuple<String> itemForName(final String name) {
|
||||||
}
|
final Optional<Tuple<String>> findFirst = this.availableValues
|
||||||
}
|
.stream()
|
||||||
|
.filter(it -> it._2 != null && it._2.equals(name))
|
||||||
private void adaptColumnWidth(final Event event) {
|
.findFirst();
|
||||||
try {
|
return findFirst.orElse(null);
|
||||||
final int currentTableWidth = this.getClientArea().width;
|
}
|
||||||
this.textCell.widthHint = currentTableWidth;
|
|
||||||
this.layout();
|
private Tuple<String> itemForId(final String id) {
|
||||||
} catch (final Exception e) {
|
final Optional<Tuple<String>> findFirst = this.availableValues
|
||||||
log.warn("Failed to adaptColumnWidth: ", e);
|
.stream()
|
||||||
}
|
.filter(it -> it._1 != null && it._1.equals(id))
|
||||||
}
|
.findFirst();
|
||||||
|
return findFirst.orElse(null);
|
||||||
private Tuple<String> itemForName(final String name) {
|
}
|
||||||
final Optional<Tuple<String>> findFirst = this.availableValues
|
|
||||||
.stream()
|
}
|
||||||
.filter(it -> it._2 != null && it._2.equals(name))
|
|
||||||
.findFirst();
|
|
||||||
if (findFirst.isPresent()) {
|
|
||||||
return findFirst.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Tuple<String> itemForId(final String id) {
|
|
||||||
final Optional<Tuple<String>> findFirst = this.availableValues
|
|
||||||
.stream()
|
|
||||||
.filter(it -> it._1 != null && it._1.equals(id))
|
|
||||||
.findFirst();
|
|
||||||
if (findFirst.isPresent()) {
|
|
||||||
return findFirst.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,122 +1,121 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Button;
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
|
|
||||||
public final class RadioSelection extends Composite implements Selection {
|
public final class RadioSelection extends Composite implements Selection {
|
||||||
|
|
||||||
private static final long serialVersionUID = 7937242481193100852L;
|
private static final long serialVersionUID = 7937242481193100852L;
|
||||||
|
|
||||||
private Listener listener = null;
|
private Listener listener = null;
|
||||||
private final Map<String, Button> radioButtons;
|
private final Map<String, Button> radioButtons;
|
||||||
|
|
||||||
RadioSelection(final Composite parent) {
|
RadioSelection(final Composite parent) {
|
||||||
super(parent, SWT.NONE);
|
super(parent, SWT.NONE);
|
||||||
final GridLayout gridLayout = new GridLayout(1, true);
|
final GridLayout gridLayout = new GridLayout(1, true);
|
||||||
gridLayout.verticalSpacing = 1;
|
gridLayout.verticalSpacing = 1;
|
||||||
gridLayout.marginLeft = 0;
|
gridLayout.marginLeft = 0;
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.marginHeight = 0;
|
||||||
gridLayout.marginWidth = 0;
|
gridLayout.marginWidth = 0;
|
||||||
setLayout(gridLayout);
|
setLayout(gridLayout);
|
||||||
|
|
||||||
this.radioButtons = new LinkedHashMap<>();
|
this.radioButtons = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type type() {
|
public Type type() {
|
||||||
return Type.RADIO;
|
return Type.RADIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
||||||
final String selectionValue = getSelectionValue();
|
final String selectionValue = getSelectionValue();
|
||||||
this.radioButtons.clear();
|
this.radioButtons.clear();
|
||||||
PageService.clearComposite(this);
|
PageService.clearComposite(this);
|
||||||
|
|
||||||
for (final Tuple<String> tuple : mapping) {
|
for (final Tuple<String> tuple : mapping) {
|
||||||
final Button button = new Button(this, SWT.RADIO);
|
final Button button = new Button(this, SWT.RADIO);
|
||||||
button.setText(tuple._2);
|
button.setText(tuple._2);
|
||||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||||
button.setLayoutData(gridData);
|
button.setLayoutData(gridData);
|
||||||
button.setData(OPTION_VALUE, tuple._1);
|
button.setData(OPTION_VALUE, tuple._1);
|
||||||
button.addListener(SWT.Selection, event -> {
|
button.addListener(SWT.Selection, event -> {
|
||||||
if (this.listener != null) {
|
if (this.listener != null) {
|
||||||
this.listener.handleEvent(event);
|
this.listener.handleEvent(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.radioButtons.put(tuple._1, button);
|
this.radioButtons.put(tuple._1, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(selectionValue)) {
|
if (StringUtils.isNotBlank(selectionValue)) {
|
||||||
select(selectionValue);
|
select(selectionValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyToolTipsForItems(final List<Tuple<String>> mapping) {
|
public void applyToolTipsForItems(final List<Tuple<String>> mapping) {
|
||||||
mapping
|
mapping
|
||||||
.stream()
|
.stream()
|
||||||
.filter(tuple -> StringUtils.isNotBlank(tuple._2))
|
.filter(tuple -> StringUtils.isNotBlank(tuple._2))
|
||||||
.forEach(tuple -> {
|
.forEach(tuple -> {
|
||||||
final Button button = this.radioButtons.get(tuple._1);
|
final Button button = this.radioButtons.get(tuple._1);
|
||||||
if (button != null) {
|
if (button != null) {
|
||||||
button.setToolTipText(Utils.formatLineBreaks(tuple._2));
|
button.setToolTipText(Utils.formatLineBreaks(tuple._2));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void select(final String key) {
|
public void select(final String key) {
|
||||||
clear();
|
clear();
|
||||||
if (StringUtils.isNotBlank(key) && this.radioButtons.containsKey(key)) {
|
if (StringUtils.isNotBlank(key) && this.radioButtons.containsKey(key)) {
|
||||||
this.radioButtons.get(key).setSelection(true);
|
this.radioButtons.get(key).setSelection(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSelectionValue() {
|
public String getSelectionValue() {
|
||||||
return this.radioButtons
|
return this.radioButtons
|
||||||
.values()
|
.values()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(button -> button.getSelection())
|
.filter(Button::getSelection)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(button -> (String) button.getData(OPTION_VALUE))
|
.map(button -> (String) button.getData(OPTION_VALUE))
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.radioButtons
|
this.radioButtons
|
||||||
.values()
|
.values()
|
||||||
.stream()
|
.forEach(button -> button.setSelection(false));
|
||||||
.forEach(button -> button.setSelection(false));
|
|
||||||
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public void setSelectionListener(final Listener listener) {
|
||||||
public void setSelectionListener(final Listener listener) {
|
this.listener = listener;
|
||||||
this.listener = listener;
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,65 +1,65 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.widget;
|
package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.swt.widgets.Control;
|
import org.eclipse.swt.widgets.Control;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
|
|
||||||
public interface Selection {
|
public interface Selection {
|
||||||
|
|
||||||
static final String OPTION_VALUE = "OPTION_VALUE";
|
String OPTION_VALUE = "OPTION_VALUE";
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
SINGLE,
|
SINGLE,
|
||||||
SINGLE_COMBO,
|
SINGLE_COMBO,
|
||||||
RADIO,
|
RADIO,
|
||||||
MULTI,
|
MULTI,
|
||||||
MULTI_COMBO,
|
MULTI_COMBO,
|
||||||
MULTI_CHECKBOX,
|
MULTI_CHECKBOX,
|
||||||
COLOR,
|
COLOR,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type();
|
Type type();
|
||||||
|
|
||||||
void applyNewMapping(final List<Tuple<String>> mapping);
|
void applyNewMapping(final List<Tuple<String>> mapping);
|
||||||
|
|
||||||
void select(final String keys);
|
void select(final String keys);
|
||||||
|
|
||||||
String getSelectionValue();
|
String getSelectionValue();
|
||||||
|
|
||||||
default String getSelectionReadableValue() {
|
default String getSelectionReadableValue() {
|
||||||
return getSelectionValue();
|
return getSelectionValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void setVisible(boolean visible);
|
void setVisible(boolean visible);
|
||||||
|
|
||||||
void setSelectionListener(Listener listener);
|
void setSelectionListener(Listener listener);
|
||||||
|
|
||||||
void setToolTipText(String tooltipText);
|
void setToolTipText(String tooltipText);
|
||||||
|
|
||||||
default void applyToolTipsForItems(final List<Tuple<String>> mapping) {
|
default void applyToolTipsForItems(final List<Tuple<String>> mapping) {
|
||||||
throw new UnsupportedOperationException("Must be implemented for this specific Selection");
|
throw new UnsupportedOperationException("Must be implemented for this specific Selection");
|
||||||
}
|
}
|
||||||
|
|
||||||
default Control adaptToControl() {
|
default Control adaptToControl() {
|
||||||
return (Control) this;
|
return (Control) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
default <T extends Selection> T getTypeInstance() {
|
default <T extends Selection> T getTypeInstance() {
|
||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ public final class SingleSelection extends Combo implements Selection {
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
super.clearSelection();
|
super.clearSelection();
|
||||||
super.setItems(this.valueMapping.toArray(new String[this.valueMapping.size()]));
|
super.setItems(this.valueMapping.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -175,7 +175,7 @@ INSERT INTO configuration_attribute VALUES
|
||||||
(304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'),
|
(304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
(305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'),
|
(305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
(306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''),
|
(306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''),
|
||||||
(307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, 'NSTemporaryDirectory'),
|
(307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, 'F'),
|
||||||
(308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'),
|
(308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'),
|
||||||
(309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'),
|
(309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
(310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'),
|
(310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
|
@ -263,7 +263,7 @@ INSERT INTO configuration_attribute VALUES
|
||||||
(927, 'mobileStatusBarAppearanceExtended', 'SINGLE_SELECTION', null, '0,1,2,3,4', null, null, '1'),
|
(927, 'mobileStatusBarAppearanceExtended', 'SINGLE_SELECTION', null, '0,1,2,3,4', null, null, '1'),
|
||||||
(928, 'newBrowserWindowShowURL', 'SINGLE_SELECTION', null, '0,1,2,3', null, null, '1'),
|
(928, 'newBrowserWindowShowURL', 'SINGLE_SELECTION', null, '0,1,2,3', null, null, '1'),
|
||||||
(929, 'pinEmbeddedCertificates', 'CHECKBOX', null, null, null, null, 'false'),
|
(929, 'pinEmbeddedCertificates', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
(930, 'sendBrowserExamKey', 'CHECKBOX', null, null, null, null, 'false'),
|
(930, 'sendBrowserExamKey', 'CHECKBOX', null, null, null, null, 'true'),
|
||||||
(931, 'showNavigationButtons', 'CHECKBOX', null, null, null, null, 'false'),
|
(931, 'showNavigationButtons', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
(932, 'showScanQRCodeButton', 'CHECKBOX', null, null, null, null, 'false'),
|
(932, 'showScanQRCodeButton', 'CHECKBOX', null, null, null, null, 'false'),
|
||||||
(933, 'startResource', 'TEXT_FIELD', null, null, null, null, ''),
|
(933, 'startResource', 'TEXT_FIELD', null, null, null, null, ''),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue