001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.web.tags;
020    
021    import java.beans.BeanInfo;
022    import java.beans.Introspector;
023    import java.beans.PropertyDescriptor;
024    import java.io.IOException;
025    import javax.servlet.jsp.JspException;
026    import javax.servlet.jsp.JspTagException;
027    
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    
031    /**
032     * <p>Tag used to print out the String value of a user's default principal,
033     * or a specific principal as specified by the tag's attributes.</p>
034     *
035     * <p> If no attributes are specified, the tag prints out the <tt>toString()</tt>
036     * value of the user's default principal.  If the <tt>type</tt> attribute
037     * is specified, the tag looks for a principal with the given type.  If the
038     * <tt>property</tt> attribute is specified, the tag prints the string value of
039     * the specified property of the principal.  If no principal is found or the user
040     * is not authenticated, the tag displays nothing unless a <tt>defaultValue</tt>
041     * is specified.</p>
042     *
043     * @since 0.2
044     */
045    public class PrincipalTag extends SecureTag {
046    
047        //TODO - complete JavaDoc
048    
049        /*--------------------------------------------
050        |             C O N S T A N T S             |
051        ============================================*/
052    
053        /*--------------------------------------------
054        |    I N S T A N C E   V A R I A B L E S    |
055        ============================================*/
056        private static final Logger log = LoggerFactory.getLogger(PrincipalTag.class);
057    
058        /**
059         * The type of principal to be retrieved, or null if the default principal should be used.
060         */
061        private String type;
062    
063        /**
064         * The property name to retrieve of the principal, or null if the <tt>toString()</tt> value should be used.
065         */
066        private String property;
067    
068        /**
069         * The default value that should be displayed if the user is not authenticated, or no principal is found.
070         */
071        private String defaultValue;
072    
073        /*--------------------------------------------
074        |         C O N S T R U C T O R S           |
075        ============================================*/
076    
077        /*--------------------------------------------
078        |  A C C E S S O R S / M O D I F I E R S    |
079        ============================================*/
080    
081    
082        public String getType() {
083            return type;
084        }
085    
086    
087        public void setType(String type) {
088            this.type = type;
089        }
090    
091    
092        public String getProperty() {
093            return property;
094        }
095    
096    
097        public void setProperty(String property) {
098            this.property = property;
099        }
100    
101    
102        public String getDefaultValue() {
103            return defaultValue;
104        }
105    
106    
107        public void setDefaultValue(String defaultValue) {
108            this.defaultValue = defaultValue;
109        }
110    
111        /*--------------------------------------------
112        |               M E T H O D S               |
113        ============================================*/
114    
115    
116        @SuppressWarnings({"unchecked"})
117        public int onDoStartTag() throws JspException {
118            String strValue = null;
119    
120            if (getSubject() != null) {
121    
122                // Get the principal to print out
123                Object principal;
124    
125                if (type == null) {
126                    principal = getSubject().getPrincipal();
127                } else {
128                    principal = getPrincipalFromClassName();
129                }
130    
131                // Get the string value of the principal
132                if (principal != null) {
133                    if (property == null) {
134                        strValue = principal.toString();
135                    } else {
136                        strValue = getPrincipalProperty(principal, property);
137                    }
138                }
139    
140            }
141    
142            // Print out the principal value if not null
143            if (strValue != null) {
144                try {
145                    pageContext.getOut().write(strValue);
146                } catch (IOException e) {
147                    throw new JspTagException("Error writing [" + strValue + "] to JSP.", e);
148                }
149            }
150    
151            return SKIP_BODY;
152        }
153    
154        @SuppressWarnings({"unchecked"})
155        private Object getPrincipalFromClassName() {
156            Object principal = null;
157    
158            try {
159                Class cls = Class.forName(type);
160                principal = getSubject().getPrincipals().oneByType(cls);
161            } catch (ClassNotFoundException e) {
162                if (log.isErrorEnabled()) {
163                    log.error("Unable to find class for name [" + type + "]");
164                }
165            }
166            return principal;
167        }
168    
169    
170        private String getPrincipalProperty(Object principal, String property) throws JspTagException {
171            String strValue = null;
172    
173            try {
174                BeanInfo bi = Introspector.getBeanInfo(principal.getClass());
175    
176                // Loop through the properties to get the string value of the specified property
177                boolean foundProperty = false;
178                for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
179                    if (pd.getName().equals(property)) {
180                        Object value = pd.getReadMethod().invoke(principal, (Object[]) null);
181                        strValue = String.valueOf(value);
182                        foundProperty = true;
183                        break;
184                    }
185                }
186    
187                if (!foundProperty) {
188                    final String message = "Property [" + property + "] not found in principal of type [" + principal.getClass().getName() + "]";
189                    if (log.isErrorEnabled()) {
190                        log.error(message);
191                    }
192                    throw new JspTagException(message);
193                }
194    
195            } catch (Exception e) {
196                final String message = "Error reading property [" + property + "] from principal of type [" + principal.getClass().getName() + "]";
197                if (log.isErrorEnabled()) {
198                    log.error(message, e);
199                }
200                throw new JspTagException(message, e);
201            }
202    
203            return strValue;
204        }
205    }