001 /* 002 * ---------------------------------------------------------------------- 003 * Copyright (C) 2009 Enrique Lara (k957@68k.org) 004 * 005 * TinLizard is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public License 007 * as published by the Free Software Foundation; either version 3.0 008 * of the License, or (at your option) any later version. 009 * 010 * TinLizard is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License 016 * along with TinLizard. If not, see http://www.gnu.org/licenses/. 017 * ---------------------------------------------------------------------- 018 */ 019 package tinlizard.web; 020 021 import tinlizard.annotation.security.RolesAllowed; 022 023 import tinlizard.dataload.DataLoader; 024 025 import tinlizard.model.Codeline; 026 import tinlizard.model.Dependency; 027 import tinlizard.model.Policy; 028 import tinlizard.model.Project; 029 import tinlizard.model.TinLizard; 030 import tinlizard.model.TinLizardConfig; 031 import tinlizard.model.User; 032 import tinlizard.model.View; 033 034 import tinlizard.util.JndiUtil; 035 import tinlizard.util.Messages; 036 037 import java.io.Writer; 038 import java.net.URL; 039 import java.util.Collection; 040 import java.util.Date; 041 import java.util.HashMap; 042 import java.util.Locale; 043 import java.util.Map; 044 045 import javax.servlet.RequestDispatcher; 046 import javax.servlet.http.HttpSession; 047 048 import org.apache.log4j.Logger; 049 050 import org.codehaus.plexus.ContainerConfiguration; 051 import org.codehaus.plexus.DefaultContainerConfiguration; 052 import org.codehaus.plexus.DefaultPlexusContainer; 053 import org.codehaus.plexus.PlexusContainer; 054 import org.codehaus.plexus.PlexusContainerException; 055 import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 056 import org.codehaus.plexus.util.StringUtils; 057 058 import org.kohsuke.stapler.StaplerRequest; 059 import org.kohsuke.stapler.StaplerResponse; 060 import org.kohsuke.stapler.export.Exported; 061 062 /** 063 * Root Object for Stapler. 064 * 065 * Misc. 066 * XXX search admin - clear indexes, index some, index all? 067 * XXX security CRUD per object or object group (project+codelines, users, views). 068 * XXX Artifact - get consumers needs to check groupId as well. 069 * XXX bubble up 0001 error in meaningful way to UI. 070 * XXX obtain effective-pom dependencies. 071 * XXX advanced search. 072 * 073 * Model 074 * XXX codeline create/lastmodified confusing - for the record in TL or for the actual codeline? maybe "admins" can set both? 075 * XXX project.getCodelineCount(Policy p); 076 * XXX user.getName(); 077 * XXX reconsider changelog/scm interface. 078 * TODO: codeline - a depends on b. 079 * TODO: codeline - merge target 080 * TODO: reporting/summary - codeline/merge plan based on codeline merge target and inter-dependencies. 081 * TODO: codeline search - "bachelors" - no one depends on it? 082 * 083 * Activities: 084 * TODO: activity log for all events: Activity: EntityType,ID,Action,Actor,TimeStamp,IP. 085 * 086 * UI: 087 * XXX: scm connection in codelines.tag 088 * TODO: edit items "in place", instead of having to go to configure screen. 089 * TODO: "logan's run" age of codelines/views on UI. max age? configurable? 090 * TODO: ICONS: http://tango.freedesktop.org/Tango_Desktop_Project 091 * TODO: List out mvn scm:checkout commands to get all projects in view. 092 * TODO: implement HttpDeletable for applicable classes. 093 * 094 * Eclipse Integration 095 * TODO: eclipse - plugin to get codeline policy? right-click -> Team -> getCodelinePolicy(). 096 * 097 * Hudson Integration: 098 * TODO: include sample scripts to show updating TinLizard from Hudson/Redmine, etc. 099 */ 100 public final class TinLizardWeb extends ObjectWeb<TinLizard> { 101 private static final String PLEXUS_CONFIG = "/META-INF/plexus/tinlizard.xml"; 102 private static final TinLizardWeb INSTANCE = new TinLizardWeb(); 103 private static final Logger LOG = Logger.getLogger(TinLizardWeb.class); 104 private PlexusContainer plexus; 105 106 private TinLizardWeb() { 107 } 108 109 protected TinLizard getSubject() { 110 return TinLizard.getInstance(); 111 } 112 113 public String getName() { 114 return TinLizard.getInstance().getName(); 115 } 116 117 public static TinLizardWeb getInstance() { 118 return INSTANCE; 119 } 120 121 @Exported 122 public Date getCreated() { 123 return TinLizard.getInstance().getCreated(); 124 } 125 126 @Exported 127 public String getCreatedBy() { 128 return TinLizard.getInstance().getCreatedBy(); 129 } 130 131 @Exported 132 public Date getLastModified() { 133 return TinLizard.getInstance().getLastModified(); 134 } 135 136 @Exported 137 public String getLastModifiedBy() { 138 return TinLizard.getInstance().getLastModifiedBy(); 139 } 140 141 @Exported 142 public String getVersion() { 143 return TinLizard.getInstance().getVersion(); 144 } 145 146 public void startup(String home) { 147 try { 148 ContainerConfiguration c = new DefaultContainerConfiguration(); 149 Map<Object, Object> context = new HashMap<Object, Object>(); 150 context.putAll(JndiUtil.getContextMap()); 151 context.put("TINLIZARD_HOME", home); 152 c.setContext(context); 153 154 URL configuration = getClass().getResource(PLEXUS_CONFIG); 155 c.setContainerConfigurationURL(configuration); 156 157 plexus = new DefaultPlexusContainer(c); 158 159 TinLizardConfig tlconfig = (TinLizardConfig) plexus.lookup(TinLizardConfig.ROLE); 160 TinLizard.initialize(tlconfig); 161 162 if (JndiUtil.getBoolean(JndiUtil.LOADTESTDATA)) { 163 LOG.debug("Loading Test Data."); 164 new DataLoader().run(); 165 } 166 } catch (PlexusContainerException e) { 167 throw new IllegalStateException(Messages.error_0500(), e); 168 } catch (ComponentLookupException e) { 169 throw new IllegalStateException(Messages.error_0501(), e); 170 } 171 } 172 173 public void shutdown() { 174 plexus.dispose(); 175 } 176 177 public ProjectCollectionWeb getAllProjects() { 178 Collection<Project> allProjects = Project.findAll(); 179 180 if (allProjects != null) { 181 return new ProjectCollectionWeb(allProjects, Messages._AllProjects()); 182 } else { 183 return null; 184 } 185 } 186 187 public ProjectWeb getProject(final String name) { 188 if (LOG.isDebugEnabled()) { 189 LOG.debug(name); 190 } 191 192 Project p = Project.findByName(name); 193 194 if (p != null) { 195 return new ProjectWeb(p); 196 } else { 197 return null; 198 } 199 } 200 201 public ViewWeb getDefaultView() { 202 return new ViewWeb(View.getDefaultView()); 203 } 204 205 public ViewCollectionWeb getAllViews() { 206 Collection<View> allViews = View.findAll(); 207 208 if (allViews != null) { 209 return new ViewCollectionWeb(allViews, Messages._AllViews()); 210 } else { 211 return null; 212 } 213 } 214 215 public ViewWeb getView(final String name) { 216 View view = View.findByName(name); 217 218 if (view != null) { 219 return new ViewWeb(view); 220 } else { 221 return null; 222 } 223 } 224 225 public CodelineCollectionWeb getAllCodelines() { 226 Collection<Codeline> allCodelines = Codeline.findAll(); 227 228 if (allCodelines != null) { 229 return new CodelineCollectionWeb(allCodelines, Messages._AllCodelines()); 230 } else { 231 return null; 232 } 233 } 234 235 public CodelineCollectionWeb getActiveCodelines() { 236 Collection<Codeline> allCodelines = Codeline.findAllActive(); 237 238 if (allCodelines != null) { 239 return new CodelineCollectionWeb(allCodelines, Messages._ActiveCodelines()); 240 } else { 241 return null; 242 } 243 } 244 245 public CodelineCollectionWeb getRecentlyModified() { 246 Collection<Codeline> allCodelines = Codeline.findRecentlyModified(5); //XXX days ago as user input. 247 248 if (allCodelines != null) { 249 return new CodelineCollectionWeb(allCodelines, Messages._RecentlyModifiedCodelines()); 250 } else { 251 return null; 252 } 253 } 254 255 public UserCollectionWeb getAllUsers() { 256 Collection<User> allUsers = User.findAll(); 257 258 if (allUsers != null) { 259 return new UserCollectionWeb(allUsers, Messages._AllUsers()); 260 } else { 261 return null; 262 } 263 } 264 265 public UserWeb getUser(final String name) { 266 User user = User.getUserByName(name, false); 267 268 if (user != null) { 269 return new UserWeb(user); 270 } else { 271 return null; 272 } 273 } 274 275 @RolesAllowed(RoleNames.USER) 276 public void doPreferences(final StaplerRequest request, final StaplerResponse response) throws Exception { 277 String username = request.getUserPrincipal().getName(); 278 279 User.getUserByName(username, true); //Auto-create user if not exist. 280 281 response.sendRedirect(request.getContextPath() + "/user/" + username + "/configure"); 282 } 283 284 public void applyTemplate(final Object it, final String template, final Writer out, final Locale locale, final String username) { 285 getSubject().getMashDao().applyTemplate(it, template, out, Locale.getDefault(), username); 286 } 287 288 public PolicyWeb getDefaultPolicy() { 289 return new PolicyWeb(Policy.getDefaultPolicy()); 290 } 291 292 public PolicyCollectionWeb getAllPolicies() { 293 Collection<Policy> allPolicies = Policy.findAll(); 294 295 if (allPolicies != null) { 296 return new PolicyCollectionWeb(allPolicies, Messages._AllPolicies()); 297 } else { 298 return null; 299 } 300 } 301 302 public PolicyWeb getPolicy(final String name) { 303 Policy policy = Policy.findByName(name); 304 305 if (policy != null) { 306 return new PolicyWeb(policy); 307 } else { 308 return null; 309 } 310 } 311 312 public DependencyWeb getDependency(final String groupId) { 313 if (StringUtils.isNotBlank(groupId)) { 314 Dependency dependency = new Dependency(); 315 dependency.setGroupId(groupId); 316 317 return new GroupWeb(dependency); 318 } 319 320 return null; 321 } 322 323 @RolesAllowed(RoleNames.USER) 324 public void doAddProject(final StaplerRequest request, final StaplerResponse response) throws Exception { 325 Project p = new Project(); 326 request.bindParameters(p, "project."); 327 328 Codeline c = new Codeline(); 329 request.bindParameters(c, "codeline."); 330 331 User user = new User(); 332 request.bindParameters(user, "owner."); 333 user = User.getUserByName(user.getName(), true); 334 335 boolean updateFromPom = Boolean.parseBoolean(request.getParameter("updateFromPom")); 336 337 Project project = Project.add(user, p, c, updateFromPom); 338 response.sendRedirect(request.getContextPath() + "/project/" + project.getName()); 339 } 340 341 @RolesAllowed(RoleNames.USER) 342 public void doAddView(final StaplerRequest request, final StaplerResponse response) throws Exception { 343 View view = new View(); 344 request.bindParameters(view, "view."); 345 346 view.add(); 347 response.sendRedirect(request.getContextPath() + "/view/" + view.getName()); 348 } 349 350 @RolesAllowed(RoleNames.ADMIN) 351 public void doAddPolicy(final StaplerRequest request, final StaplerResponse response) throws Exception { 352 Policy policy = new Policy(); 353 request.bindParameters(policy, "policy."); 354 355 policy.add(); 356 response.sendRedirect(request.getContextPath() + "/policy/" + policy.getName()); 357 } 358 359 /** 360 * Let container managed security handle the rest. 361 */ 362 public void doLogin(final StaplerRequest request, final StaplerResponse response) throws Exception { 363 response.sendRedirect(request.getContextPath()); 364 } 365 366 public void doLogout(final StaplerRequest request, final StaplerResponse response) throws Exception { 367 if (LOG.isDebugEnabled() && (request.getUserPrincipal() != null)) { 368 LOG.debug((("doLogout:" + request.getUserPrincipal()) != null) ? request.getUserPrincipal().getName() : ""); 369 } 370 371 HttpSession session = request.getSession(false); 372 373 if (session != null) { 374 session.invalidate(); 375 } 376 377 response.sendRedirect(request.getContextPath()); 378 } 379 380 public void doSearch(final StaplerRequest request, final StaplerResponse response) throws Exception { 381 String type = request.getParameter("type"); 382 String query = request.getParameter("query"); 383 384 final Object results; 385 386 if ("Dependency".equals(type)) { 387 Collection<Dependency> dependencies = Dependency.search(query); 388 results = new DependencyCollectionWeb(dependencies, Messages._SearchResults(query)); 389 } else { 390 Collection<Codeline> codelines = Codeline.search(query); 391 results = new CodelineCollectionWeb(codelines, Messages._SearchResults(query)); 392 } 393 394 request.setAttribute(javax.servlet.jsp.jstl.core.Config.FMT_FALLBACK_LOCALE, response.getLocale()); 395 396 RequestDispatcher view = request.getView(results, "index.jsp"); 397 view.include(request, response); 398 } 399 400 @RolesAllowed(RoleNames.USER) 401 public void doIndexAll(final StaplerRequest request, final StaplerResponse response) throws Exception { 402 getSubject().indexAll(); 403 404 response.sendRedirect(request.getContextPath()); 405 } 406 }