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 */
019package org.apache.shiro.web.tags;
020
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024import javax.servlet.jsp.JspException;
025import javax.servlet.jsp.JspTagException;
026import java.beans.BeanInfo;
027import java.beans.Introspector;
028import java.beans.PropertyDescriptor;
029import java.io.IOException;
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 */
045public 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 LOGGER = 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 (LOGGER.isErrorEnabled()) {
163                LOGGER.error("Unable to find class for name [" + type + "]");
164            }
165        }
166        return principal;
167    }
168
169    private String getPrincipalProperty(Object principal, String property) throws JspTagException {
170        String strValue = null;
171
172        try {
173            BeanInfo bi = Introspector.getBeanInfo(principal.getClass());
174
175            // Loop through the properties to get the string value of the specified property
176            boolean foundProperty = false;
177            for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
178                if (pd.getName().equals(property)) {
179                    Object value = pd.getReadMethod().invoke(principal, (Object[]) null);
180                    strValue = String.valueOf(value);
181                    foundProperty = true;
182                    break;
183                }
184            }
185
186            if (!foundProperty) {
187                final String message = "Property [" + property + "] not found in principal of type ["
188                        + principal.getClass().getName() + "]";
189                if (LOGGER.isErrorEnabled()) {
190                    LOGGER.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 ["
197                    + principal.getClass().getName() + "]";
198            if (LOGGER.isErrorEnabled()) {
199                LOGGER.error(message, e);
200            }
201            throw new JspTagException(message, e);
202        }
203
204        return strValue;
205    }
206}