Hi Jeanne, Skinning is part of the scope of JSF 2.0, see under Adoption at http://jcp.org/en/jsr/detail?id=314. However, so far skinning is not part of the spec, see the public review for reference. Also, time is running short and I fear that skinning might not be part of the final spec if I don't try a more direct approach (that might still utterly fail). I did came up with these design ideas over quite some time thinking about what I liked and disliked about Trinidad's skinning and how to make it more modular. I believe it's very important as JSF 2.0 includes means to have rich extension libraries work better together by standardizing AJAX and Resource serving. However, if users wanting to use IceFaces and Trinidad together, for example, have got to define their home made skins in two different files declared in two different ways, it might irritate them. Therefore, skinning is an important part of better extension interoperability imho, thus why I want to propose something to the EG.
So the goal I'd like to reach here is an overall review and design that could be done quite fast to support all required feature while allowing maximum flexibility. At the same time, I'll about it with some other Fujitsu resources internally. Finally, and hopefully in time and to members agreement, I'll propose the API to the JSR-314 EG as Fujitsu Limited representative. I cannot say what happen on the EG that would be against the legal agreement we have as participant. However, nothing prevents me from designing something with the Apache MyFaces community then propose it since it's totally non binding and might not make it through and isn'T an API being currently talked about or contributed by someone else. Also, even if the API didn't make it through, if the design is done very well, maybe the EG would consider it during another iteration if it become a de facto (like Facelets did). So, in all cases, it wouldn't be lost. That being said, if we go into more politics matters, if the design pleases you and the remaining of the community, that would most likely put three votes on my side for the proposal, Oracle's, Apache's and Fujitsu's. That's not everyone though and the design should also fit RichFaces and IceFaces needs that I'm no expert with. Anyone with experience with those technologies could help with the design. At first I didn't really think about bringing those ideas here, but the post kind of triggered it. Anyway, I believe it's all good since it would put more of the community in the process for that very important part. On the other hand, as soon as I propose something on the EG, as far as I can understand the legal bindings, I'll no longer be able to talk about it on the mailing list until a public review including it is released as I'll be bound by the EG secrecy clause, MyFaces community members would have to get informed through Martin who's representing Apache on the EG and only if you signed a non-disclosure agreement (would have to check with legal-discuss about that part). See: http://jcp.org/aboutJava/communityprocess/JSPA2.pdf The most important parts in that case are: *Definitions* *1.3 Confidential Information*: information exchanged between You and Sun, or among You, Sun and other Members, during the term of this Agreement concerning the development of Output or other activities under the Process (defined below) that: (i) if disclosed in tangible form (which may include information made available over the Internet), is clearly labeled as confidential or proprietary at the time of disclosure; or (ii) if disclosed orally, is identified as confidential (or words of similar import) at the time of disclosure and is confirmed in a writing delivered to such receiving party within thirty (30) days after disclosure. For example, Confidential Information may take the form of draft specifications promulgated by the Spec Lead and the Expert Group, and comments relating thereto from Members. 9. Confidentiality. A. Duty of Confidentiality. Prior to Public Review, or other public dissemination of the Spec by the Spec Lead (which the Spec Lead may authorize unless prohibited or otherwise limited by the Process), or the elapse of three years from the date of disclosure in the case of Information exchanged within the Expert Group and not incorporated into the Spec, Confidential Information shall neither be: (i) disclosed to third parties that are not also Members; nor (ii) used for any purpose unrelated to the goals of the JCP which include, for example, the development or review of draft Specifications and development of commercial products or services intended for use in conjunction with compliant implementations of the Spec. A receiving party's obligations to protect Confidential Information shall expire upon release of the pertinent Spec for Public Review or other public dissemination of the Spec by the Spec Lead, except for Confidential Information exchanged within the Expert Group and not incorporated into the Spec, which shall be maintained as confidential for a period of three (3) years after disclosure. B. Limitations. This Agreement imposes no obligation upon the receiving party with respect to Information which: (a) was in the possession of, or was known by, the receiving party prior to its receipt from disclosing party, without an obligation to maintain its confidentiality; (b) is or becomes generally known to the public without violation of this Agreement; (c) is obtained by the receiving party from a third party, without an obligation to keep such information confidential; or (d) is independently developed by the receiving party without use of Information disclosed by another party. Disclosure of Information by the receiving party is not prohibited if prior notice is given to disclosing party and such disclosure is: (a) compelled pursuant to a legal proceeding or (b) otherwise required by law. Parties may disclose Information to subsidiaries and/or to third party contractors who have entered into a written confidentiality agreement at least as restrictive as the terms of this Section 9. Basically, this post it not within my duty of confidentiality for now since I didn't propose it. Once I do propose it, then talking about what I meant with something said in the design, about what a class is doing in the form prior to the proposal and such other discussion would fall under B. However, all talk about how it's evolving on the EG discussion would definitely be under A and not a limitation as discussion transform the orginal product, creating a new one and thus I wouldn't be able to claim a right on B.(a) or (d). I love legal agreements... Always clear and freedom prone... Anyway, it's what it is, so the point now is to tell me if you like or not my design and if there's something you dislike, how should it be fixed. ~ Simon On Fri, Dec 5, 2008 at 5:38 PM, Jeanne Waldman <[EMAIL PROTECTED]>wrote: > Hi Simon, > I'm a little unclear on the process. Can you explain? Like did you come up > with these ideas and then we all discuss them or is there an Expert Group > you will send these to ( you say that at the end) and they will be the > primary owner of this project? Is the idea that we would someday take > skinning out of Trinidad and it would use these libraries? > > Thanks, > Jeanne > > Simon Lessard wrote, On 12/5/2008 10:21 AM PT: > >> I agree with most of these statements, but I would start even higher than >> that, like defining the base interfaces and access classes. >> >> For instance, I think it's safe to assume that a Skin class or interface >> should exists. Let assume all interfaces for now as it takes less >> characters. Now, from where and how should the Skin be available for a given >> FacesContext. Personally I believe a Skin should be linked to a RenderKit >> (or a common base RenderKit class for all MyFaces extensions if not in the >> standard), but let assume work on the API for now for the sake of the >> discussion. >> >> So for now we have: >> >> public interface Skin >> { >> public String getResourceBundle(); >> } >> >> public abstract class RenderKit >> { >> public abstract Skin getSkin(FacesContext context); >> } >> >> So far so good, but now that opens some issues that will themselves >> explode into more: >> >> 1. Should the way the RenderKit locates the current Skin standardized? >> 2. How do we define the contract ensuring that the Skin get >> rendered on the page? >> 3. What other functionalities should be standarized in the Skin >> >> interface? >> >> *Issue 1: Current skin localization* >> Personally I chose yes to that question since it allow a standardized way >> to define skins. Let use Trinidad's skin-family notion here, but with the >> way renderKitId is defined, that's the view root and a factory implementing >> decorator pattern. So we add >> >> public class UIViewRoot >> { >> public String getSkinFamily(); >> public void setSkinFamily(String skinFamily); >> } >> >> public abstract class SkinFactory implements FacesWrapper<SkinFactory> >> { >> public abstract void addSkin(String skinFamily, String renderKitId, >> Skin skin); >> public abstract Skin getSkin(String skinFamily, String renderKitId); >> public abstract Collection<String> getSkinFamilies(); >> public SkinFactory getWrapped() >> { >> return null; >> } >> } >> >> *Sub-issue 1.1: Default SkinFactory implementation behavior* >> Additional Exceptions >> public class SkinException extends FacesException >> { >> // Provides all 4 common Exception constructors >> } >> >> public class SkinInitializationException extends SkinException >> { >> // Provides all 4 common Exception constructors >> } >> >> Additional interface >> /** >> * Implementations of this interface are in charge of creating Skin >> instances in an implementation specific manner. >> */ >> public interface SkinLoader >> { >> /** >> * Creates a new <code>Skin</code> instance the specified skinFamily >> and parameters. There's no garanteed as of what >> * parameters will be present in the Map argument and the creation >> should fails if those parameters are not correct >> * for the specific implementation. >> * >> * @throws SkinInitializationException if the provided parameter are >> not enough to create the <code>Skin</code> instance >> */ >> public Skin loadSkin(String skinFamily, String resourceBundle, >> Map<String, String> parameters); >> } >> >> Addition to faces-config.xml: >> <application> >> <default-skin-family/> >> </application> >> <skin> >> <skin-family/> >> <render-kit-id/> >> <description/> >> <skin-loader-class/> >> <resource-bundle/> >> <skin-loader-parameters> >> <map-entries/> >> </skin-loader-parameters> >> </skin> >> >> Note that this solution makes RenderKit.getSkin more an utility method >> than anything, except if an extension decides to override it (would probably >> be the casew ith Trinidad, at least to start to use trinidad-config.xml, or >> later to add .pda or .desktop to the current skinFamily). >> >> Also, the framework should probably provide some implementations of >> SkinLoader out-of-the-box, most likely ClassSkinLoader expecting a skinClass >> parameter and a CSSSkinLoader receiving a cssResourcePath parameter. >> (Trinidad would mostl ikely provide an XSSSkinLoader for example) >> >> *Issue 2: Skin content rendering* >> How should rendering be handled? Should it be handled as an added >> ResourceDependency just before rendering or as an additional contract for >> the default HtmlRenderer for HtmlHead? The latter sounds better, but how >> should it be implemented? target would obviously be "head", but then a >> public Resource Skin.getContentResource() method could be required and this >> might imply some changes to the ResourceHandler specification so that it can >> locate the Skin instance in order to be able to serve the Resource's content >> (effective CSS content) to the agent. I like the Resource version, but I >> have more thinking to do about how to implement this, maybe involving a >> reserved resourceIdentifier structure/syntax >> >> *Issue 3: Skin features* >> Additional class >> public abstract class Icon extends Resource >> { >> /** >> * Gets the key within the skin's ResourceBundle to the description of >> this icon. The description can be used >> * as an alternate text for the icon to improve accessibility for >> example. >> */ >> public abstract String getDescriptionKey(); >> /** >> * Gets the name of this icon. >> */ >> public abstract String getName(); >> >> /** >> * Gets the effective style class of this icon within the skin. >> */ >> public abstract String getStyleClass(); >> } >> >> public interface Skin >> { >> public Icon getIcon(String iconName); >> >> public String getProperty(String propertyKey); >> >> public String getResourceBundle(); >> >> public String getStyleClass(String selectorKey); >> } >> >> *Sub-issue 3.1: style class / property / icon access strategy* >> Trinidad uses String keys to access style classes within the skin. That >> strategy is very flexible, but alas very slow, thanks to String.hashCode() >> being linear and uncached. So, even if String.intern() is called on all >> selectors within a given skin, the gain will only be on String.equals, >> making it O(1) instead of O(n). Even if this is better than nothing, >> especially it there's a collision, the overall complexity of looking up a >> selector remains O(n) with the length of the key. So, the overall cost of >> skinning with this strategy is averageLengthOfKey * >> averageAmountOfComponentPerPage * averageAmountOfHtmlElementPerComponent >> (assuming each element gets its own style class which is required for >> maximum customizability). Another, but a little bit more complex, solution >> is also possible using a "dynamic enum" alike to PropertyKey in Trinidad. So >> I'd like something like: >> >> public abstract class SkinKeyPart >> { >> public String name(); >> >> public int ordinal(); >> } >> >> public class Namespace extends SkinKeyPart >> { >> /** >> * Find or create the Namespace instance with the specified name. >> */ >> public static Namespace getInstance(String name); >> } >> >> public class ComponentKey extends SkinKeyPart >> { >> /** >> * Find or create the ComponentKey instance with the specified name. >> */ >> public static ComponentKey getInstance(String name); >> } >> >> public class ComponentPartKey extends SkinKeyPart >> { >> /** >> * Find or create the ComponentPartKey instance with the specified >> name. >> */ >> public static ComponentPartKey getInstance(String name); >> } >> >> public class ComponentStateKey extends SkinKeyPart >> { >> /** >> * Find or create the ComponentStateKey instance with the specified >> name. >> */ >> public static ComponentPartKey getInstance(String name); >> } >> >> public abstract class SkinNode >> { >> public abstract String[] getStyleClasses(); >> public abstract String getProperty(String propertyName); >> public abstract Icon getIcon(String iconName); >> public abstract SkinNode getSubPart(ComponentPartKey partKey); >> } >> >> public interface Skin >> { >> /** >> * Still exists to get properties global to the whole skin if someone >> ever need that feature >> */ >> public String getProperty(String propertyName); >> >> /** >> * No change here >> */ >> public String getResourceBundle(); >> >> public String getSkinNode(Namespace ns, ComponentKey component); >> >> public String getSkinNode(Namespace ns, ComponentKey component, >> ComponentStateKey state); >> >> public String getSkinNode(Namespace ns, ComponentKey component, >> ComponentStateKey... states); >> } >> >> That solution has the advantage of being very fast, actually a real O(1) >> for every node access assuming the Renderer gathers the keys it needs during >> instanciation. Then the "root" SkinNode could probably be located using a >> base Renderer class and passed to a custom encoding method (Trinidad's >> encodeAll for example). Of course, the skin loaders would have to create >> skin instances structuring the selectors accordingly. A base class for Skin >> with such feature should probably be provided if this solution is wanted in >> order to make new implementation of Skin easier to create. >> >> *PENDIND issues:* >> PENDING: Should the path leverage the Resource API instead and receive a >> library-name, library-version, resource-name and resource-version instead? >> >> PENDING: A CompositeSkin class should probably be provided and most likely >> usable from the configuration, should it be using a specific loader with >> parameters or have a fully-fledged tag like <composite-skin> for example? >> The use of such skin implementation would be for users using multiple >> libraries, each with very different RenderKit implementations. A composite >> RenderKit class could also be useful here. >> >> PENDING: Should Trinidad's SkinAddition notion be considered? SkinAddition >> provides a way to add skin elements to an existing skin based on its id. It >> would be possible to leverage that by using the skin-family/render-kit-id >> tuple instead. Another option would be to simply have the default >> SkinFactory implementation to automatically agreggate the Skin instances >> with the same skin-family and render-kit-id into a CompositeSkin instance. >> >> PENDING: Should additional metadata be added to <renderer> tag to define >> the supported skin selector for tooling purpose? This point is dependant on >> the content of the Skin interface and the strategy chosen to access the >> properties/style class of a given component and/or one of its sub-element. >> >> PENDING: Should the effective CSS properties stay accessible in memory or >> otherwise from the Skin instance? If so, should they be modifiable? I tend >> toward no for both for performance issues. Of course this could be also left >> as an optional operation of the interface, throwing >> UnsupportedOperationException in most case but at least leaving the >> possibility for special implementations requiring it. This point also impact >> issue 2 in some ways. >> >> PENDING: About Icon, it should probably also leverage the Resource API, >> how should that be implemented? >> >> PENDING: Icon's styleClass, should the instance directly return an >> effective class or should it rather return a selector that would then be >> looked up from the Skin? I prefer the latter, but then there's the Stirng >> issue so maybe the icon would have to return an optimized selector key as >> mentioned in 3.1 >> >> PENDING: Solution to issue 3.1, although very fast and flexible, can be an >> linkage nightmare. For example, a node for component "inputText" with states >> "disabled" and "required" should be able to link to the component part node >> for part "label" of "inputText" without any state defined if needed. The >> performance gain of 3.1 is great, the implementation complexity isn't. >> Still, personally I don't have any problem throwing complexity at >> implementor's head if the users can feel the difference. Another option >> would be to remove the "state" complexity part and have a predefined style >> class syntax for those. That solution is what Trinidad does. However, this >> solution is not as flexible as it doesn't allow to switch Icon dynamically >> depending on the component's state. >> >> PENDING: Solution 3.1 don't allow state to be applied on the component's >> sub parts. Most of the time it's not an issue, but we have one such use case >> with Trinidad's train component where the train itself doesn't have a state, >> but each of its station (sub-part) can be visited/unvisited and/or selected >> and/or disabled. If 3.1 is kept, should it be tweaked even more to allow a >> sub-part state on a per part basis as well? This makes the linkage a >> nightmare on Elm Street candidate, althoguh adding more potential to the >> Skin >> >> PENDING: Trinidad supports a "selector redirect" feature that is used with >> the delegate renderer architecture to have specified selectorKeys >> transformed into a different one. This is implemented as a Map<String >> oldName, String newName> redirection map. Should such feature be >> standardized? If so and 3.1 is adressed then it will have to be well thought >> about. Also, trinidad support a single of those map applied as a set on the >> skin instance, I believe it should be a push / pop instead if standardized. >> >> PENDING: Should there be any inheritance/cascading behavior defined by >> default? I tend toward no here. >> >> PENDING: Should the skin have a getTranslatedResource(FacesContext >> context, String resourceKey) instead of the getResourceBundle method? >> >> >> That's about it for now. My main blocker is 3.1 and I'd like to come up >> with something better for it before presenting it to the EG, same holds true >> with various links to the Resource API (icons, the skin itself, etc) >> >> >> Regards, >> >> ~ Simon >> >> >> On Fri, Dec 5, 2008 at 10:33 AM, Andrew Robinson < >> [EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>> >> wrote: >> >> > All other frameworks use >> > component attributes for this, but Trinidad puts it in these >> > non-intuitive skinning keys. >> >> Sorry, had one more comment right after I hit send again. Maybe just >> having default component attributes for a web app would satisfy the >> need. Like a way to say 'partialSumbit' should be defaulted to true on >> all tr:commandLink. Then all the skin properties could be converted to >> attributes and have their defaults set in a common location (like what >> the skin does). >> >> This would be much more useful and flexible as then page developers >> can make exceptions to the rule. >> >> >>
