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 }