Vojtech Szocs has posted comments on this change.

Change subject: userportal, webadmin: branding support.
......................................................................


Patch Set 19: (58 inline comments)

Reviewed patch set 19 so some comments might not be relevant, Alex - let me 
know if you have any questions.

So the general strategy is to take default styles away from GWT application and 
externalize them as a separate (default) branding package. On one side, this 
goes against GWT design philosophy that GWT output should be as optimized and 
performant as possible (i.e. inline default styles right into application 
code). On the other side, I agree that having a separate (default) branding 
package essentially communicates clear interface with branding package authors.

Given above mentioned pros/cons, I guess that in this particular case, having 
default styles externalized is OK. However, be advised that this approach might 
lead to "jumpy UI" effect when loading styles for the first time (application 
code has been loaded, but styles are still loading).

Some general comments:
* please use config/engine-code-format.xml (Java code formatting rules for 
Eclipse) and *always try to format new code* (ctrl-shift-F in Eclipse), I see 
that you use default (80-char) limit whereas engine-code-format.xml defines 
120-char limit
* please avoid "//comment" and use "// comment" according to formatting rules 
mentioned above (i.e. format source code properly)
* please use newlines to separate different logical elements to improve code 
readability
* using "final" for method arguments has little-to-none performance gain in 
modern JVMs (server-side code) and *zero* performance gain in GWT (client-side 
code), which makes "final" redundant, except for cases when it's required 
according to Java language spec

....................................................
File 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/branding/BrandingManager.java
Line 16: import org.codehaus.jackson.node.ObjectNode;
Line 17: import org.ovirt.engine.core.utils.EngineLocalConfig;
Line 18: 
Line 19: /**
Line 20:  * This class manages the available branding themes.
"... branding themes and localized messages."
Line 21:  */
Line 22: public class BrandingManager {
Line 23:     /**
Line 24:      * The default branding path.


Line 39:      * The regex pattern to use to determine if a directory should be 
used
Line 40:      * as a branding directory. The pattern is '^\d?\d\-.+' So any two 
digits
Line 41:      * followed by a dash will do.
Line 42:      */
Line 43:     private static final Pattern DIRECTORY_PATTERN = 
Pattern.compile(".+\\.brand"); //$NON-NLS-1$
The pattern differes from Javadoc, why?
Line 44: 
Line 45:     private static final int CURRENT_BRANDING_VERSION = 1;
Line 46:     /**
Line 47:      * A list of available {@code BrandingTheme}s.


Line 41:      * followed by a dash will do.
Line 42:      */
Line 43:     private static final Pattern DIRECTORY_PATTERN = 
Pattern.compile(".+\\.brand"); //$NON-NLS-1$
Line 44: 
Line 45:     private static final int CURRENT_BRANDING_VERSION = 1;
Please add Javadoc here, this is important constant!

Additionally, newline after this would improve readability.
Line 46:     /**
Line 47:      * A list of available {@code BrandingTheme}s.
Line 48:      */
Line 49:     private List<BrandingTheme> themes = null;


Line 45:     private static final int CURRENT_BRANDING_VERSION = 1;
Line 46:     /**
Line 47:      * A list of available {@code BrandingTheme}s.
Line 48:      */
Line 49:     private List<BrandingTheme> themes = null;
null assignment is redundant here.
Line 50: 
Line 51:     /**
Line 52:      * The root path of the branding themes.
Line 53:      */


Line 73:      * @return A {@code List} of {@code BrandingTheme}s.
Line 74:      */
Line 75:     public List<BrandingTheme> getBrandingThemes() {
Line 76:         if (themes == null && brandingRootPath.exists() && 
brandingRootPath.isDirectory()
Line 77:                 && brandingRootPath.canRead()) {
Why are we reloading branding themes only for the first time, i.e. when "themes 
== null"?

Since "themes" is local state specific to BrandingManager class, you'd have to 
restart Engine after you alter "brandingRootPath" directory content, is this 
really what we want?
Line 78:             themes = new ArrayList<BrandingTheme>();
Line 79:             List<File> directories = Arrays.asList(
Line 80:                     brandingRootPath.listFiles(new FileFilter() {
Line 81:                         @Override


Line 132:         ObjectNode node = new ObjectMapper().createObjectNode();
Line 133:         for (Map.Entry<String, String> entry : keyValues.entrySet()) {
Line 134:             node.put(entry.getKey(), entry.getValue());
Line 135:         }
Line 136:         return node.size() > 0 ? node.toString() : null;
Why is returning null on empty message object important?

In other words, empty JavaScript object can serve as "null object" indicating 
there are no custom messages.
Line 137:     }
Line 138: 
Line 139:     /**
Line 140:      * Get the root path of the branding files.


....................................................
File 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/branding/BrandingTheme.java
Line 18:  *  <li>The path to the theme</li>
Line 19:  *  <li>The name of the style sheet associated with the theme</li>
Line 20:  * </ul>
Line 21:  */
Line 22: public class BrandingTheme {
Please use newline (below) to separate inner type members.
Line 23:     /**
Line 24:      * Enumeration specifying which application type to get a
Line 25:      * style sheet for.
Line 26:      */


Line 113:      * @param brandingRootPath The root of the path to the branding 
theme,
Line 114:      * @param brandingVersion The version to load, if the version 
don't match the load will fail.
Line 115:      * @return {@code true} if successfully loaded, {@code false} 
otherwise.
Line 116:      */
Line 117:     public boolean load(final String brandingPath, final File 
brandingRootPath, final int brandingVersion) {
Assuming load() is meant to be one-time operation, I suggest to remove load() 
method parameters, make relevant fields final, and introduce constructor that 
sets those fields.
Line 118:         path = brandingPath.substring(
Line 119:                 brandingRootPath.getAbsolutePath().
Line 120:                         length());
Line 121:         filePath = brandingPath;


Line 122:         available = false;
Line 123:         FileInputStream propertiesFile;
Line 124:         try {
Line 125:             propertiesFile = new FileInputStream(brandingPath
Line 126:                     + "/" + BRANDING_PROPERTIES_NAME); //$NON-NLS-1$
String brandingPropertiesFile = brandingPath + "/" + BRANDING_PROPERTIES_NAME;

(Try to avoid code duplication.)
Line 127:             brandingProperties.load(propertiesFile);
Line 128:             available = brandingVersion == getVersion();
Line 129:             if (!available) {
Line 130:                 log.warn("Unable to load branding theme, mismatched 
version: " //$NON-NLS-1$


Line 124:         try {
Line 125:             propertiesFile = new FileInputStream(brandingPath
Line 126:                     + "/" + BRANDING_PROPERTIES_NAME); //$NON-NLS-1$
Line 127:             brandingProperties.load(propertiesFile);
Line 128:             available = brandingVersion == getVersion();
Design of this method looks strange to me ... first it initializes 
"brandingProperties" field and then it calls method (getVersion) that assumes 
"brandingProperties" has already been set.
Line 129:             if (!available) {
Line 130:                 log.warn("Unable to load branding theme, mismatched 
version: " //$NON-NLS-1$
Line 131:                     + getVersion() + " wanted version: " + 
brandingVersion); //$NON-NLS-1$
Line 132:             }


Line 134:             // Unable to load properties file, disable theme.
Line 135:             log.warn("Unable to load properties file for " 
//$NON-NLS-1$
Line 136:                     + "theme located here:"//$NON-NLS-1$
Line 137:                     + brandingPath + "/" //$NON-NLS-1$
Line 138:                     + BRANDING_PROPERTIES_NAME);
See my comment above on "brandingPropertiesFile".

Maybe also include "e" (exception) as log.warn method argument?
Line 139:         }
Line 140:         return available;
Line 141:     }
Line 142:     /**


Line 150:     /**
Line 151:      * Getter for the webadmin style sheet name.
Line 152:      * @return The {@code String} representing the style sheet.
Line 153:      */
Line 154:     public final String getWebadminStyleSheetName() {
Why is this method necessary? The caller should have appropriate 
ApplicationType enum instance, we can just call getCssKey() on that instance.
Line 155:         return 
brandingProperties.getProperty(ApplicationType.WEBADMIN.getCssKey());
Line 156:     }
Line 157: 
Line 158:     /**


Line 158:     /**
Line 159:      * Getter for the user portal style sheet name.
Line 160:      * @return The {@code String} representing the style sheet.
Line 161:      */
Line 162:     public final String getUserPortalStyleSheetName() {
Why is this method necessary? The caller should have appropriate 
ApplicationType enum instance, we can just call getCssKey() on that instance.
Line 163:         return 
brandingProperties.getProperty(ApplicationType.USER_PORTAL.getCssKey());
Line 164:     }
Line 165: 
Line 166:     /**


Line 190:      * Get the style sheet type based on the passed in {@code 
ApplicationType}.
Line 191:      * @param type The application type to get the style sheet string 
for.
Line 192:      * @return A {@code String} representation of the style sheet 
name.
Line 193:      */
Line 194:     public final String getThemeStyleSheet(final ApplicationType 
type) {
The implementation of this method looks weird to me.

You can just call "brandingProperties.getProperty(type.getCssKey())" - what's 
the purpose of the switch statement?

(The "default" switch case is redundant, given that ApplicationType only has 
two values.)
Line 195:         String result = null;
Line 196:         switch (type) {
Line 197:         case USER_PORTAL:
Line 198:             result = getUserPortalStyleSheetName();


Line 212:      * @return A {@code ResourceBundle} containing messages.
Line 213:      */
Line 214:     public final ResourceBundle getMessagesBundle() {
Line 215:         // Default to US Locale.
Line 216:         return getMessagesBundle(Locale.US);
Locale.US should be externalized as constant into LocaleFilter class (try to 
avoid code duplication).
Line 217:     }
Line 218: 
Line 219:     /**
Line 220:      * Get the theme messages resource bundle.


Line 229:                     new URL[] {
Line 230:                             themeDirectory.toURI().toURL() });
Line 231:             result = ResourceBundle.getBundle(
Line 232:                     brandingProperties.getProperty(MESSAGES_KEY).
Line 233:                             replaceAll("\\.properties", ""), 
//$NON-NLS-1$ //$NON-NLS-2$
We should use regex to remove ".properties" suffix, instead of using 
replaceAll() method.
Line 234:                     locale,
Line 235:                     urlLoader);
Line 236:         } catch (IOException e) {
Line 237:             // Unable to load messages resource bundle.


Line 235:                     urlLoader);
Line 236:         } catch (IOException e) {
Line 237:             // Unable to load messages resource bundle.
Line 238:             log.warn("Unable to read message resource " //$NON-NLS-1$
Line 239:                     + "bundle, returning null"); //$NON-NLS-1$
Maybe also include "e" (exception) as log.warn method argument?
Line 240:         }
Line 241:         return result;
Line 242:     }
Line 243: 


....................................................
File 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/BrandingServlet.java
Line 56:         String fullPath = getFullPath(path);
Line 57:         if (fullPath != null) {
Line 58:             File file = new File(fullPath);
Line 59:             if (!file.exists() || !file.canRead() || 
file.isDirectory()) {
Line 60:                 log.error("Unable to locate file, will send a 404 
error response."); //$NON-NLS-1$
I suggest to log requested file path as well, i.e. see PluginResourceServlet 
for reference.
Line 61:                 response.sendError(HttpServletResponse.SC_NOT_FOUND);
Line 62:             } else {
Line 63:                 String etag = generateEtag(file);
Line 64:                 if 
(etag.equals(request.getHeader(GwtDynamicHostPageServlet.


Line 104:      * @return A full absolute path for the passed in path.
Line 105:      */
Line 106:     String getFullPath(final String path) {
Line 107:         String result = null;
Line 108:         if (path != null && ServletUtils.isSane(path)) {
Why are we checking isSane for "path" (request.getPathInfo) instead of full 
(resolved) path to requested resource?

In other words:

isSane(path)

vs.

isSane(brandingManager.getBrandingRootPath().getAbsolutePath() + path)
Line 109:             // Return a result relative to the branding root path.
Line 110:             result = 
brandingManager.getBrandingRootPath().getAbsolutePath() + path;
Line 111:         } else {
Line 112:             log.error("The path \"" + path + "\" is not sane"); 
//$NON-NLS-1$ //$NON-NLS-2$


....................................................
File 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/GwtDynamicHostPageServlet.java
Line 30: 
Line 31: /**
Line 32:  * Renders the HTML host page of a GWT application.
Line 33:  * <p>
Line 34:  * Embeds additional data (JavaScript objects) into the host page.
config/engine-code-format.xml (Java code formatting rules for Eclipse) 
specifies following:

<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>

In general this means "maximum line width is 120 characters".

Please start using above mentioned code formatting rules, instead of 
Eclipse-default 80 character limit.
Line 35:  * By default, information about the currently logged-in
Line 36:  * user is included via {@code userInfo} object.
Line 37:  */
Line 38: public abstract class GwtDynamicHostPageServlet extends HttpServlet {


Line 35:  * By default, information about the currently logged-in
Line 36:  * user is included via {@code userInfo} object.
Line 37:  */
Line 38: public abstract class GwtDynamicHostPageServlet extends HttpServlet {
Line 39:     /**
Please use newline to separate inner class members... (better code readability, 
whitespace really matters!)
Line 40:      * The values of this enum are used by the MD5 sum calculation to
Line 41:      * determine if the values have changed.
Line 42:      */
Line 43:     public enum MD5Attributes {


Line 112:         request.setAttribute(MD5Attributes.ATTR_STYLES.getKey(), 
brandingThemes);
Line 113:         // Set the messages that need to be replaced.
Line 114:         request.setAttribute(MD5Attributes.ATTR_MESSAGES.getKey(), 
getBrandingMessages(getLocaleFromRequest(request)));
Line 115:         // Set the default theme path.
Line 116:         request.setAttribute(ATTR_THEME_PATH, "theme"); //$NON-NLS-1$
Do we really need to set request attribute in order to share common "theme" 
constant across different components?
Line 117:         // Set class of servlet
Line 118:         
request.setAttribute(MD5Attributes.ATTR_APPLICATION_TYPE.getKey(), 
getApplicationType());
Line 119:         // Set attribute for userInfo object
Line 120:         VdcUser loggedInUser = 
getLoggedInUser(request.getSession().getId());


Line 161:     private Locale getLocaleFromRequest(final ServletRequest request) 
{
Line 162:         Locale locale = (Locale) 
request.getAttribute(LocaleFilter.LOCALE); //$NON-NLS-1$
Line 163:         if (locale == null) {
Line 164:             //If no locale defined, default back to US locale.
Line 165:             locale = Locale.US;
Please add new constant, i.e. "public static final Locale defaultLocale = 
Locale.US" into LocaleFilter, and replace "Locale.US" usage here and in other 
related classes to use the "defaultLocale" constant.
Line 166:         }
Line 167:         return locale;
Line 168:     }
Line 169: 


Line 167:         return locale;
Line 168:     }
Line 169: 
Line 170:     /**
Line 171:      * Get a JavaScript associated array string that define the 
branding messages.
associated -> associative
Line 172:      * @param locale {@code Locale} to use to look up the messages.
Line 173:      * @return The messages as a {@code String}
Line 174:      */
Line 175:     private String getBrandingMessages(final Locale locale) {


....................................................
File 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/UserPortalHostPageServlet.java
Line 21:     }
Line 22: 
Line 23:     @Override
Line 24:     public ApplicationType getApplicationType() {
Line 25:         return BrandingTheme.ApplicationType.USER_PORTAL;
Why use "BrandingTheme.ApplicationType" when return type already uses 
"ApplicationType" directly?
Line 26:     }


....................................................
File 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/server/gwt/WebAdminHostPageServlet.java
Line 41:     }
Line 42: 
Line 43:     @Override
Line 44:     public ApplicationType getApplicationType() {
Line 45:         return BrandingTheme.ApplicationType.WEBADMIN;
Why use "BrandingTheme.ApplicationType" when return type already uses 
"ApplicationType" directly?
Line 46:     }
Line 47: 
Line 48:     @Override
Line 49:     protected boolean filterQueries() {


....................................................
File 
frontend/webadmin/modules/frontend/src/main/resources/META-INF/resources/GwtHostPage.jsp
Line 7:     <meta http-equiv="X-UA-Compatible" content="IE=edge">
Line 8:     <meta name="gwt:property" 
content="locale=${requestScope['locale']}">
Line 9:     <c:if test="${requestScope['brandingStyle'] != null}">
Line 10:         <c:forEach items="${requestScope['brandingStyle']}" 
var="theme">
Line 11:         <c:if 
test="${theme.getThemeStyleSheet(requestScope['applicationType']) != null}">
Put indentation here for better readability, this is nested under <c:forEach>
Line 12:     <link rel="stylesheet" type="text/css" 
href="${pageContext.request.contextPath}/${requestScope['theme']}${theme.path}/${theme.getThemeStyleSheet(requestScope['applicationType'])}">
Line 13:         </c:if>
Line 14:         </c:forEach>
Line 15:     </c:if>


Line 8:     <meta name="gwt:property" 
content="locale=${requestScope['locale']}">
Line 9:     <c:if test="${requestScope['brandingStyle'] != null}">
Line 10:         <c:forEach items="${requestScope['brandingStyle']}" 
var="theme">
Line 11:         <c:if 
test="${theme.getThemeStyleSheet(requestScope['applicationType']) != null}">
Line 12:     <link rel="stylesheet" type="text/css" 
href="${pageContext.request.contextPath}/${requestScope['theme']}${theme.path}/${theme.getThemeStyleSheet(requestScope['applicationType'])}">
Again, wrong indentation, code readability matters!
Line 13:         </c:if>
Line 14:         </c:forEach>
Line 15:     </c:if>
Line 16:     <script type="text/javascript">


....................................................
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/utils/DynamicConstants.java
Line 8: /**
Line 9:  * This class contains dynamic messages available to the application. 
This
Line 10:  * class is a singleton.
Line 11:  */
Line 12: public class DynamicConstants {
Please add newline below, helps code readability.
Line 13:     protected static final String LOGIN_HEADER_LABEL = 
"login_header_label"; //$NON-NLS-1$
Line 14:     protected static final String MAIN_HEADER_LABEL = 
"main_header_label"; //$NON-NLS-1$
Line 15:     protected static final String COPY_RIGHT_NOTICE = 
"copy_right_notice"; //$NON-NLS-1$
Line 16:     protected static final String APPLICATION_TITLE = 
"application_title"; //$NON-NLS-1$


Line 13:     protected static final String LOGIN_HEADER_LABEL = 
"login_header_label"; //$NON-NLS-1$
Line 14:     protected static final String MAIN_HEADER_LABEL = 
"main_header_label"; //$NON-NLS-1$
Line 15:     protected static final String COPY_RIGHT_NOTICE = 
"copy_right_notice"; //$NON-NLS-1$
Line 16:     protected static final String APPLICATION_TITLE = 
"application_title"; //$NON-NLS-1$
Line 17:     protected static final String VERSION_ABOUT = "version_about"; 
//$NON-NLS-1$
Consider adding enum to contain message keys (without the prefix).
Line 18: 
Line 19:     /**
Line 20:      * The name under which the dictionary will appear in the host 
page.
Line 21:      */


Line 28: 
Line 29:     /**
Line 30:      * Protected default constructor.
Line 31:      */
Line 32:     @Inject
@Inject is redundant here, its purpose is to inject any additional dependencies 
(instances bound in Ginjector context).

For no-arg constructor, there are no dependencies so no need for @Inject, 
Guice/GIN honors no-arg constructor when binding types, assuming there are no 
other constructors.
Line 33:     public DynamicConstants() {
Line 34:         dictionary = null;
Line 35:         try {
Line 36:             dictionary = 
Dictionary.getDictionary(MESSAGES_DICTIONARY_NAME);


Line 30:      * Protected default constructor.
Line 31:      */
Line 32:     @Inject
Line 33:     public DynamicConstants() {
Line 34:         dictionary = null;
This statement is redundant.
Line 35:         try {
Line 36:             dictionary = 
Dictionary.getDictionary(MESSAGES_DICTIONARY_NAME);
Line 37:         } catch (MissingResourceException mre) {
Line 38:             // Do nothing, the dictionary doesn't exist.


Line 34:         dictionary = null;
Line 35:         try {
Line 36:             dictionary = 
Dictionary.getDictionary(MESSAGES_DICTIONARY_NAME);
Line 37:         } catch (MissingResourceException mre) {
Line 38:             // Do nothing, the dictionary doesn't exist.
I suggest to log this using GWT java.util.logging emulation.
Line 39:         }
Line 40:     }
Line 41: 
Line 42:     /**


Line 46:      * @param fallback The fallback in case the dictionary cannot find 
a string associated with the key.
Line 47:      * @return A {@code String} looked up using the key from the
Line 48:      * {@code Dictionary}.
Line 49:      */
Line 50:     protected String getString(final String key, final String 
fallback) {
See my comment above - adding enum for possible keys, the enum would also 
contain fallback (default) value, this would improve overall code 
maintainability and remove need for subclassing DynamicConstants altogether.

(In addition, if DynamicConstants is really meant to be subclassed, it should 
be marked as "abstract" anyway.)
Line 51:         String result = fallback;
Line 52:         try {
Line 53:             if (dictionary != null) {
Line 54:                 result = dictionary.get(key);


Line 53:             if (dictionary != null) {
Line 54:                 result = dictionary.get(key);
Line 55:             }
Line 56:         } catch (MissingResourceException mre) {
Line 57:             // Do nothing, the key doesn't exist.
I suggest to log this using GWT java.util.logging emulation.
Line 58:         }
Line 59:         return result;
Line 60:     }


....................................................
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/dialog/SimpleDialogPanel.ui.xml
Line 108: 
Line 109:       <g:FlowPanel>
Line 110:               <g:FlowPanel addStyleNames="{style.header}">
Line 111:                       <g:SimplePanel ui:field="logoPanel" 
addStyleNames="{style.headerLeftPanel}">
Line 112:                               <g:Image 
styleName='obrand_dialogLogoImage' url="clear.cache.gif" />
Please explain why is "clear.cache.gif" necessary here?
Line 113:                       </g:SimplePanel>
Line 114:                       <g:FlowPanel 
addStyleNames="{style.obrand_headerCenterPanel}">
Line 115:                               <g:FlowPanel 
ui:field="headerContainerPanel">
Line 116:                                       <g:SimplePanel 
ui:field="headerTitlePanel" addStyleNames="{style.headerTitle}" />


Line 122:                               </g:FlowPanel>
Line 123:                       </g:FlowPanel>
Line 124:                       <g:SimplePanel 
addStyleNames="{style.headerRightPanel}">
Line 125:                               <g:FlowPanel>
Line 126:                                       <g:Image 
styleName='obrand_dialogHeaderImage' url="clear.cache.gif" />
Same as my comment above.
Line 127:                                       <g:PushButton 
ui:field='closeIconButton' addStyleNames="{style.closeIconButton}">
Line 128:                                               <g:upFace 
image='{resources.dialogIconClose}' />
Line 129:                                               <g:downFace 
image='{resources.dialogIconCloseDown}' />
Line 130:                                               <g:upHoveringFace 
image='{resources.dialogIconCloseRollover}' />


....................................................
File 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/dialog/tab/DialogTab.java
Line 30: 
Line 31:     interface Style extends CssResource {
Line 32:         String obrand_active();
Line 33: 
Line 34:         String inactive();
If we externalize "active" why leave "inactive" non-externalized? (for 
consistency)
Line 35:     }
Line 36: 
Line 37:     @UiField
Line 38:     FocusPanel tabContainer;


....................................................
File 
frontend/webadmin/modules/userportal-gwtp/src/main/java/org/ovirt/engine/ui/userportal/ApplicationDynamicConstants.java
Line 11:  * associated {@code ApplicationConstants} message.
Line 12:  *
Line 13:  * This is for the user portal
Line 14:  */
Line 15: public class ApplicationDynamicConstants extends DynamicConstants {
Why do we need to subclass DynamicConstants?

It seems that UserPorta/WebAdmin-specific ApplicationConstants reference is the 
only thing needed here.

So I suggest following:
- rename UserPortalDynamicConstants to something more appropriate, i.e. 
ConstantWithDefault enum
- move ConstantWithDefault enum to DynamicConstants
- make DynamicConstants @Inject CommonApplicationConstants (available in 
gwt-common)
- if necessary, move ApplicationConstants methods up into 
CommonApplicationConstants

Result: no DynamicConstants subclassing necessary, less code to maintain.
Line 16:     /**
Line 17:      * This enum contains the keys for the {@code Dictionary} to look 
up dynamic
Line 18:      * messages from the host page. If the particular message is not 
found, the
Line 19:      * fall-back is used.


....................................................
File 
frontend/webadmin/modules/userportal-gwtp/src/main/java/org/ovirt/engine/ui/userportal/section/login/view/LoginPopupView.ui.xml
Line 114: 
Line 115:       <d:SimplePopupPanel ui:field="popup" width="480px">
Line 116:               <d:header>
Line 117:                       <g:HorizontalPanel 
styleName="{loginPopupStyle.loginPopupHeader}">
Line 118:                               <g:Image 
styleName="obrand_loginPopupHeaderLogoImage" url="clear.cache.gif" />
Same as before, why is "clear.cache.gif" necessary here?
Line 119:                               <g:HTMLPanel 
styleName="{loginPopupStyle.obrand_loginPopupHeaderCenter}">
Line 120:                                       <g:Label ui:field="headerLabel" 
addStyleNames="{loginPopupStyle.headerLabelStyle}"/>
Line 121:                               </g:HTMLPanel>
Line 122:                               <g:Image 
styleName="obrand_loginPopupHeaderImage" url="clear.cache.gif" />


Line 118:                               <g:Image 
styleName="obrand_loginPopupHeaderLogoImage" url="clear.cache.gif" />
Line 119:                               <g:HTMLPanel 
styleName="{loginPopupStyle.obrand_loginPopupHeaderCenter}">
Line 120:                                       <g:Label ui:field="headerLabel" 
addStyleNames="{loginPopupStyle.headerLabelStyle}"/>
Line 121:                               </g:HTMLPanel>
Line 122:                               <g:Image 
styleName="obrand_loginPopupHeaderImage" url="clear.cache.gif" />
Same question as above.
Line 123:                       </g:HorizontalPanel>
Line 124:               </d:header>
Line 125: 
Line 126:               <d:content>


....................................................
File frontend/webadmin/modules/userportal-gwtp/src/main/webapp/WEB-INF/web.xml
Line 1: <web-app xmlns="http://java.sun.com/xml/ns/javaee"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
Line 2:         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"; version="3.0">
Line 3: 
Line 4:         <display-name>oVirt UserPortal UI</display-name>
Line 5:     <!-- Filters -->
Please add newline above for better readability.

Also. please reformat this XML file, I saw that you use 4-space convention for 
indentation, or just use TAB characters.
Line 6:     <filter>
Line 7:       <filter-name>LocaleFilter</filter-name>
Line 8:       
<filter-class>org.ovirt.engine.core.utils.servlet.LocaleFilter</filter-class>
Line 9:     </filter>


Line 4:         <display-name>oVirt UserPortal UI</display-name>
Line 5:     <!-- Filters -->
Line 6:     <filter>
Line 7:       <filter-name>LocaleFilter</filter-name>
Line 8:       
<filter-class>org.ovirt.engine.core.utils.servlet.LocaleFilter</filter-class>
This definition should go into 
frontend/src/main/resources/META-INF/web-fragment.xml

(The point of web fragment is to define common servlet/filter names for easy 
use within specific web applications.)
Line 9:     </filter>
Line 10:     <filter-mapping>
Line 11:       <filter-name>LocaleFilter</filter-name>
Line 12:       
<url-pattern>/org.ovirt.engine.ui.userportal.UserPortal/*</url-pattern>


Line 27:                <servlet-name>GenericApiServlet</servlet-name>
Line 28:                
<url-pattern>/org.ovirt.engine.ui.userportal.UserPortal/GenericApiGWTService</url-pattern>
Line 29:        </servlet-mapping>
Line 30: 
Line 31:     <servlet-mapping>
See my comment above, please reformat this XML file.
Line 32:         <servlet-name>BrandingServlet</servlet-name>
Line 33:         <url-pattern>/theme/*</url-pattern>
Line 34:     </servlet-mapping>
Line 35: 


....................................................
File 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/ApplicationDynamicConstants.java
Line 10:  * associated {@code ApplicationConstants} message.
Line 11:  *
Line 12:  * This is for the web admin
Line 13:  */
Line 14: public class ApplicationDynamicConstants extends DynamicConstants {
See my comment in userportal ApplicationDynamicConstants.java - we should 
simplify the implementation, it also seems there's a lot of unnecessary code 
duplicity between these two ApplicationDynamicConstants classes.
Line 15:     /**
Line 16:      * This enum contains the keys for the {@code Dictionary} to look 
up dynamic
Line 17:      * messages from the host page. If the particular message is not 
found, the
Line 18:      * fall-back is used.


....................................................
File 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/login/view/LoginPopupView.ui.xml
Line 111: 
Line 112:       <d:SimplePopupPanel ui:field="popup" width="480px">
Line 113:               <d:header>
Line 114:                       <g:HorizontalPanel 
styleName="{loginPopupStyle.loginPopupHeader}">
Line 115:                               <g:Image 
styleName="obrand_loginPopupHeaderLogoImage" url="clear.cache.gif" />
Same as before, why is "clear.cache.gif" necessary here?
Line 116:                               <g:HTMLPanel 
styleName="{loginPopupStyle.obrand_loginPopupHeaderCenter}">
Line 117:                                       <g:Label ui:field="headerLabel" 
addStyleNames="{style.headerLabelStyle}"/>
Line 118:                               </g:HTMLPanel>
Line 119:                               <g:Image 
styleName="obrand_loginPopupHeaderImage" url="clear.cache.gif" />


Line 115:                               <g:Image 
styleName="obrand_loginPopupHeaderLogoImage" url="clear.cache.gif" />
Line 116:                               <g:HTMLPanel 
styleName="{loginPopupStyle.obrand_loginPopupHeaderCenter}">
Line 117:                                       <g:Label ui:field="headerLabel" 
addStyleNames="{style.headerLabelStyle}"/>
Line 118:                               </g:HTMLPanel>
Line 119:                               <g:Image 
styleName="obrand_loginPopupHeaderImage" url="clear.cache.gif" />
Same question as above.
Line 120:                       </g:HorizontalPanel>
Line 121:               </d:header>
Line 122: 
Line 123:               <d:content>


....................................................
File 
frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/MainSectionView.ui.xml
Line 1
Line 2
Line 3
Line 4
Line 5
Are CSS definitions in "defines.css" used anywhere else, do we still need this 
CSS file?


....................................................
File packaging/branding/ovirt.brand/branding.properties
Line 1: #OVIRT branding properties.
See my comment in README.branding - this file should document purpose and other 
details on supported options.
Line 2: 
Line 3: #style sheets.
Line 4: user_portal_css=ovirt_user_portal.css
Line 5: web_admin_css=ovirt_web_admin.css


....................................................
File packaging/branding/ovirt.brand/ovirt_messages.properties
Line 1: #Available properties:
See my comment in README.branding - this file should document individual 
message keys.
Line 2: #common
Line 3: obrand.common.login_header_label=Open Virtualization Manager
Line 4: obrand.common.copy_right_notice=
Line 5: obrand.common.version_about=oVirt Engine Version:


....................................................
File packaging/branding/ovirt.brand/ovirt_user_portal.css
Line 1: @import url("ovirt_common.css");
See my comment in README.branding - this file should document individual CSS 
classes.
Line 2: 
Line 3: /* MainTabBasicView.ui.xml */
Line 4: .obrand_borderPanelStyle {
Line 5:     border-color: #719823;


....................................................
File packaging/branding/ovirt.brand/ovirt_web_admin.css
Line 1: @import url("ovirt_common.css");
See my comment in README.branding - this file should document individual CSS 
classes.
Line 2: 
Line 3: /* HeaderView.ui.xml */
Line 4: .obrand_logo {
Line 5:     float: left;


....................................................
File README.branding
Line 6: 
Line 7: ovirt-engine supports pluggable branding that may effect the user 
interface
Line 8: themes and selected strings. There may be several branding packages
Line 9: installed in specific order, each package overrides the previous ones
Line 10: for the resources it defines.
Overall, this README file is excellent! Helped me understand a lot about how 
the branding works just by reading this file.
Line 11: 
Line 12: PACKAGE FORMAT
Line 13: --------------
Line 14: 


Line 11: 
Line 12: PACKAGE FORMAT
Line 13: --------------
Line 14: 
Line 15: branding.properties
Which properties in branding.properties file are mandatory and which are 
optional?

Please specify this information here as well as within reference oVirt branding 
package's branding.properties file, for posterity (see my comment below).
Line 16:     This is the main properties file that defines where the branding
Line 17:     resources can be found. Resources are relative to 
branding.properties.
Line 18: 
Line 19:     user_portal_css - Css to inject into user portal.


Line 20:     web_admin_css - Css to inject into web admin.
Line 21:     messages - Standard java message bundle.
Line 22:     version - The version of the branding in the package. Only versions
Line 23:       that match the one defined in the engine will be loaded. The 
current
Line 24:       version is 1.
I suggest to put this information also inside reference oVirt branding 
package's branding.properties file, using properties (#) comment syntax.

"The current version is" information deserves special attention, I suggest to 
have a separate paragraph for it.

Also, if a branding package defines "version=2" and Engine supports "version=1" 
shouldn't we aim for backwards compatibility, so that branding package authors 
don't have to maintain multiple packages for each version?

(In other words, what's the reason behind exact version checking?)
Line 25: 
Line 26: CSS INJECTION
Line 27: 
Line 28: CSS are injected in the reverse order of the branding package order, 
this


Line 25: 
Line 26: CSS INJECTION
Line 27: 
Line 28: CSS are injected in the reverse order of the branding package order, 
this
Line 29: way the last css's styles overrides the previous ones.
I think this paragraph should be removed, as mentioned below we use standard 
conf.d convention to impose order among multiple branding packages.

Assuming CSS style sheets are applied sequentially, the latter one always 
overrides the former one.
Line 30: 
Line 31: The oVirt UI is broken up into three distinct modules at this point.
Line 32:  * User Portal
Line 33:  * Web Admin


Line 126: EXAMPLE
Line 127: -------
Line 128: If you look in packaging/branding/ovirt.brand you will see a 
functional
Line 129: example branding theme which just happens to be the default oVirt 
theme.
Line 130: You will notice the following files:
If we already have a reference oVirt branding package that is "complete" in 
terms of CSS classes and message keys, what's the point of providing full 
listing of CSS classes + message keys in this file?

Wasn't the reference oVirt branding package supposed to serve as, well, 
reference to these CSS classes + message keys, communicating clear (and 
complete) interface for branding package authors?

(In other words, do we really want to maintain full CSS class + message key 
list in this README file?)

I suggest to remove CSS class + message key listing in this README file (except 
for examples, of course) and provide extra documentation (comments) right 
inside reference oVirt branding package's CSS and properties files.

For CSS this means adding extra comments to .obrand_* classes in:
- ovirt_user_portal.css + any @import'ed css files
- ovirt_web_admin.css + any @import'ed css files

For messages this means adding extra comments to obrand.* message keys in:
- ovirt_messages.properties
(no need to do this for ovirt_messages_xx_YY.properties since this is just 
locale-specific message value override)

(Additionally, in future, we can consider auto-generating the list of brandable 
CSS classes and message keys. My point is to avoid maintaining same information 
in different files by hand.)
Line 131: 
Line 132: 1. branding.properties, This is the main properties file defining
Line 133:   the branding properties.
Line 134: 2. user_portal.css, The user portal style sheet file.


Line 151: own directory.
Line 152: 
Line 153: The branding directory is treated as a standard conf.d, in which 
directories
Line 154: are sorted by name, each package is read by order and overrides
Line 155: the previous ones.
+1

Using standard conf.d convention to impose order among multiple branding 
packages sounds reasonable here.

Just wondering, when you install branding package, will this package 
automatically assume it has order N and put its files into say 
${engine_syconfdir}/branding/N-PKGNAME.brand directory?


--
To view, visit http://gerrit.ovirt.org/13181
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: comment
Gerrit-Change-Id: I4a8a426ce7d688d33c5ae2b70632c836843106b2
Gerrit-PatchSet: 19
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Alexander Wels <aw...@redhat.com>
Gerrit-Reviewer: Alex Lourie <alou...@redhat.com>
Gerrit-Reviewer: Alexander Wels <aw...@redhat.com>
Gerrit-Reviewer: Alon Bar-Lev <alo...@redhat.com>
Gerrit-Reviewer: Barak Azulay <bazu...@redhat.com>
Gerrit-Reviewer: Daniel Erez <de...@redhat.com>
Gerrit-Reviewer: Einav Cohen <eco...@redhat.com>
Gerrit-Reviewer: Eyal Edri <ee...@redhat.com>
Gerrit-Reviewer: Itamar Heim <ih...@redhat.com>
Gerrit-Reviewer: Kanagaraj M <kmayi...@redhat.com>
Gerrit-Reviewer: Moran Goldboim <mgold...@redhat.com>
Gerrit-Reviewer: Ofer Schreiber <oschr...@redhat.com>
Gerrit-Reviewer: Sahina Bose <sab...@redhat.com>
Gerrit-Reviewer: Sandro Bonazzola <sbona...@redhat.com>
Gerrit-Reviewer: Vojtech Szocs <vsz...@redhat.com>
Gerrit-Reviewer: Yair Zaslavsky <yzasl...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to