]> source.dussan.org Git - archiva.git/blob
5fd10444686ae7fd97030af098be346bf822f345
[archiva.git] /
1 package org.apache.archiva.redback.struts2.action.admin;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.archiva.redback.rbac.RBACManager;
23 import org.apache.archiva.redback.rbac.Resource;
24 import org.apache.commons.beanutils.PropertyUtils;
25 import org.apache.commons.lang.StringEscapeUtils;
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.archiva.redback.struts2.action.AbstractSecurityAction;
28 import org.apache.archiva.redback.system.SecuritySystem;
29 import org.codehaus.plexus.registry.Registry;
30 import org.apache.archiva.redback.integration.interceptor.SecureActionBundle;
31 import org.apache.archiva.redback.integration.interceptor.SecureActionException;
32 import org.apache.archiva.redback.integration.role.RoleConstants;
33 import org.springframework.context.annotation.Scope;
34 import org.springframework.stereotype.Controller;
35
36 import javax.inject.Inject;
37 import javax.inject.Named;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44
45 /**
46  * SystemInfoAction
47  *
48  * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
49  * @version $Id$
50  */
51 @Controller( "redback-sysinfo" )
52 @Scope( "prototype" )
53 public class SystemInfoAction
54     extends AbstractSecurityAction
55 {
56     // ------------------------------------------------------------------
57     // Component Requirements
58     // ------------------------------------------------------------------
59
60     /**
61      *
62      */
63     @Inject
64     private SecuritySystem securitySystem;
65
66     /**
67      *  role-hint="commons-configuration"
68      */
69     @Inject
70     @Named( value = "commons-configuration" )
71     private Registry registry;
72
73     /**
74      *  role-hint="cached"
75      */
76     @Inject
77     @Named( value = "rBACManager#cached" )
78     private RBACManager rbacManager;
79
80     // Class.getClass() and some JPOX classes
81     private static final List<String> ignoredReaders = Arrays.asList( "class", "copy" );
82
83     private static final String NULL = "&lt;null&gt;";
84
85     private static final char LN = Character.LINE_SEPARATOR;
86
87     private static final String INDENT = "  ";
88
89     private static final int MAXDEPTH = 10;
90
91     // ------------------------------------------------------------------
92     // Action Parameters
93     // ------------------------------------------------------------------
94
95     private StringBuilder details;
96
97     // ------------------------------------------------------------------
98     // Action Entry Points - (aka Names)
99     // ------------------------------------------------------------------
100
101     public String show()
102     {
103         details = new StringBuilder();
104
105         details.append( "Configuration: " );
106         dumpObject( details, registry, INDENT );
107         details.append( registry.dump() );
108         details.append( LN );
109
110         details.append( LN ).append( "<hr/>" ).append( LN );
111         details.append( "RBAC Manager: " );
112         dumpObject( details, rbacManager, INDENT );
113
114         details.append( LN ).append( "<hr/>" ).append( LN );
115         details.append( "SecuritySystem: " );
116         dumpObject( details, securitySystem, INDENT );
117
118         return SUCCESS;
119     }
120
121     private void dumpObject( StringBuilder sb, Object obj, String indent )
122     {
123         dumpObjectSwitchboard( new ArrayList<Object>(), sb, obj, indent, 0 );
124     }
125
126     /**
127      * The recursive object dumping switchboard.
128      *
129      * @param seenObjects objects already seen (to prevent cycles)
130      * @param sb          the stringbuffer to populate
131      * @param obj         the object to dump
132      * @param indent      the current indent string.
133      * @param depth       the depth in the tree.
134      */
135     private void dumpObjectSwitchboard( List<Object> seenObjects, StringBuilder sb, Object obj, String indent,
136                                         int depth )
137     {
138         if ( obj == null )
139         {
140             sb.append( NULL ).append( LN );
141             return;
142         }
143
144         if ( depth > MAXDEPTH )
145         {
146             sb.append( StringEscapeUtils.escapeHtml( "<MAX DEPTH>" ) );
147             sb.append( LN );
148             return;
149         }
150
151         depth++;
152
153         String className = obj.getClass().getName();
154
155         sb.append( '(' ).append( className ).append( ") " );
156
157         if ( obj instanceof List )
158         {
159             dumpIterator( seenObjects, sb, ( (List<?>) obj ).iterator(), indent, depth );
160         }
161         else if ( obj instanceof Set )
162         {
163             dumpIterator( seenObjects, sb, ( (Set<?>) obj ).iterator(), indent, depth );
164         }
165         else if ( obj instanceof Map )
166         {
167             dumpIterator( seenObjects, sb, ( (Map<?, ?>) obj ).entrySet().iterator(), indent, depth );
168         }
169         else if ( obj instanceof Iterator )
170         {
171             dumpIterator( seenObjects, sb, (Iterator<?>) obj, indent, depth );
172         }
173         else
174         {
175             // Filter classes that start with java or javax
176             if ( className.startsWith( "java." ) || className.startsWith( "javax." ) )
177             {
178                 sb.append( StringEscapeUtils.escapeHtml( obj.toString() ) ).append( LN );
179                 return;
180             }
181
182             // prevent cycles
183             if ( seenObjects.contains( obj ) )
184             {
185                 // No need to dump.
186                 sb.append( StringEscapeUtils.escapeHtml( "<seen already preventing cycle in dump> " ) );
187                 sb.append( LN );
188                 return;
189             }
190
191             // Adding object to seen list (to prevent cycles)
192             seenObjects.add( obj );
193
194             dumpObjectReaders( seenObjects, sb, obj, indent, depth );
195         }
196         depth--;
197     }
198
199     @SuppressWarnings( "unchecked" )
200     private void dumpObjectReaders( List<Object> seenObjects, StringBuilder sb, Object obj, String indent, int depth )
201     {
202         sb.append( obj.toString() ).append( LN );
203         String name = null;
204
205         try
206         {
207             Map<String, Object> readers = PropertyUtils.describe( obj );
208             for ( Map.Entry<String, Object> readerEntry : readers.entrySet() )
209             {
210                 name = (String) readerEntry.getKey();
211
212                 if ( ignoredReaders.contains( name ) )
213                 {
214                     // skip this reader.
215                     continue;
216                 }
217
218                 sb.append( indent );
219                 sb.append( name ).append( ':' );
220
221                 Object value = readerEntry.getValue();
222                 if ( value == null )
223                 {
224                     sb.append( NULL ).append( LN );
225                 }
226                 else
227                 {
228                     dumpObjectSwitchboard( seenObjects, sb, value, INDENT + indent, depth );
229                 }
230             }
231         }
232         catch ( Throwable e )
233         {
234             sb.append( LN ).append( indent );
235             sb.append( "Unable to read bean [" ).append( obj.getClass().getName() );
236             if ( StringUtils.isNotBlank( name ) )
237             {
238                 sb.append( ".get" ).append( StringUtils.capitalize( name ) ).append( "()" );
239             }
240             sb.append( "]: " ).append( '(' ).append( e.getClass().getName() ).append( ") " );
241             sb.append( e.getMessage() ).append( LN );
242         }
243     }
244
245     private void dumpIterator( List<Object> seenObjects, StringBuilder sb, Iterator<?> iterator, String indent,
246                                int depth )
247     {
248         sb.append( LN );
249         while ( iterator.hasNext() )
250         {
251             Object entry = iterator.next();
252             sb.append( indent );
253             dumpObjectSwitchboard( seenObjects, sb, entry, indent + " | ", depth );
254         }
255     }
256
257     // ------------------------------------------------------------------
258     // Parameter Accessor Methods
259     // ------------------------------------------------------------------
260
261     public String getDetails()
262     {
263         return details.toString();
264     }
265
266     public SecureActionBundle initSecureActionBundle()
267         throws SecureActionException
268     {
269         SecureActionBundle bundle = new SecureActionBundle();
270         bundle.setRequiresAuthentication( true );
271         bundle.addRequiredAuthorization( RoleConstants.CONFIGURATION_EDIT_OPERATION, Resource.GLOBAL );
272         return bundle;
273     }
274 }