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.model; 020 021 import tinlizard.dao.jpa.JpaDao; 022 import tinlizard.dao.jpa.Persistable; 023 024 import java.util.ArrayList; 025 import java.util.Calendar; 026 import java.util.Collection; 027 import java.util.Date; 028 import java.util.Iterator; 029 030 import javax.persistence.Column; 031 import javax.persistence.Entity; 032 import javax.persistence.EntityManager; 033 import javax.persistence.EntityNotFoundException; 034 import javax.persistence.EntityTransaction; 035 import javax.persistence.GeneratedValue; 036 import javax.persistence.GenerationType; 037 import javax.persistence.Id; 038 import javax.persistence.JoinColumn; 039 import javax.persistence.ManyToOne; 040 import javax.persistence.NamedQueries; 041 import javax.persistence.NamedQuery; 042 import javax.persistence.Query; 043 import javax.persistence.Table; 044 import javax.persistence.UniqueConstraint; 045 import javax.persistence.Version; 046 047 import org.apache.log4j.Logger; 048 import org.apache.maven.model.Model; 049 050 import org.codehaus.plexus.util.StringUtils; 051 052 import org.hibernate.annotations.Cache; 053 import org.hibernate.annotations.CacheConcurrencyStrategy; 054 import org.hibernate.search.annotations.DateBridge; 055 import org.hibernate.search.annotations.Field; 056 import org.hibernate.search.annotations.Index; 057 import org.hibernate.search.annotations.Indexed; 058 import org.hibernate.search.annotations.Resolution; 059 import org.hibernate.search.annotations.Store; 060 061 /** 062 * A Codeline is a branch. 063 */ 064 @Entity(name = "Codeline") 065 @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "tinlizard.model.Codeline") 066 @Table(name = "TL_CODELINE", uniqueConstraints = { 067 @UniqueConstraint(columnNames = { 068 "NAME", "PROJECT_ID"} 069 ) 070 , @UniqueConstraint(columnNames = { 071 "NAME", "SCM_CONNECTION"} 072 ) 073 } 074 ) 075 @NamedQueries({@NamedQuery(name = QueryNames.CODELINE_BY_NAME,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.name = ? and p = ?" + Codeline.ORDER_BY) 076 , @NamedQuery(name = QueryNames.CODELINES_MODIFIED_SINCE_DATE,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.lastModified >= ?" + Codeline.ORDER_BY + " DESC") 077 , @NamedQuery(name = QueryNames.CODELINES_BY_NAME_AND_SCM_CONNECTION,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.name = ? and o.scmConnection = ?" + Codeline.ORDER_BY) 078 , @NamedQuery(name = QueryNames.CODELINE_MAIN_LINE,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.mainLine = true and p = ?" + Codeline.ORDER_BY) 079 , @NamedQuery(name = QueryNames.CODELINES_ACTIVE,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.policy.active = true " + Codeline.ORDER_BY) 080 , @NamedQuery(name = QueryNames.CODELINES_ACTIVE_FOR_PROJECT,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where p = ? and o.policy.active = true " + Codeline.ORDER_BY) 081 , @NamedQuery(name = QueryNames.CODELINES_ACTIVE_FOR_VIEW,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where c = ? and o.policy.active = true " + Codeline.ORDER_BY) 082 , @NamedQuery(name = QueryNames.CODELINES_ALL_FOR_PROJECT,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where p = ?" + Codeline.ORDER_BY) 083 , @NamedQuery(name = QueryNames.CODELINES_ALL_FOR_VIEW,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where c = ?" + Codeline.ORDER_BY) 084 , @NamedQuery(name = QueryNames.CODELINES_ALL_FOR_POLICY,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where policy = ?" + Codeline.ORDER_BY) 085 , @NamedQuery(name = QueryNames.CODELINES_DEFINING_ARTIFACT,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.groupId = ? and o.artifactId = ? and o.version = ?" + Codeline.ORDER_BY) 086 , @NamedQuery(name = QueryNames.CODELINES_DEFINING_ARTIFACT_ANY_VERSION,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o.groupId = ? and o.artifactId = ?" + Codeline.ORDER_BY) 087 , @NamedQuery(name = QueryNames.CODELINES_DEPENDENT_ON_ARTIFACT,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o in (select distinct dep.codeline from Dependency dep where dep.groupId = ? and dep.artifactId = ? and dep.version = ?)" + Codeline.ORDER_BY) 088 , @NamedQuery(name = QueryNames.CODELINES_DEPENDENT_ON_ARTIFACT_ANY_VERSION,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where o in (select distinct dep.codeline from Dependency dep where dep.groupId = ? and dep.artifactId = ?)" + Codeline.ORDER_BY) 089 , @NamedQuery(name = QueryNames.CODELINES_BY_USER,query = Codeline.SELECT_FROM + Codeline.LEFT_JOINS + " where user = ?" + Codeline.ORDER_BY) 090 }) 091 @Indexed 092 public final class Codeline implements Persistable { 093 static final String SELECT_FROM = "select o from Codeline o "; 094 static final String LEFT_JOINS = " left join o.owner user " + " left join o.policy policy " + " left join o.view c " + " left join o.project p "; 095 static final String ORDER_BY = " order by o.name"; 096 private static final Class<Codeline> CLASS = Codeline.class; 097 private static final Logger LOG = Logger.getLogger(CLASS); 098 @Id 099 @GeneratedValue(strategy = GenerationType.AUTO) 100 @Column(name = "ID") 101 private Integer id; 102 @Column(name = "NAME", nullable = false) 103 @Field(index = Index.TOKENIZED, store = Store.NO) 104 private String name; 105 @Column(name = "CREATED", nullable = false) 106 @Field(index = Index.UN_TOKENIZED, store = Store.YES) 107 @DateBridge(resolution = Resolution.SECOND) 108 private Date created; 109 @Column(name = "CREATED_BY", nullable = false) 110 @Field(index = Index.TOKENIZED, store = Store.NO) 111 private String createdBy; 112 @Version 113 @Column(name = "LAST_MODIFIED") 114 @Field(index = Index.UN_TOKENIZED, store = Store.YES) 115 @DateBridge(resolution = Resolution.SECOND) 116 private Date lastModified; 117 @Column(name = "LAST_MODIFIED_BY") 118 @Field(index = Index.TOKENIZED, store = Store.NO) 119 private String lastModifiedBy; 120 @Column(name = "SCM_CONNECTION") 121 @Field(index = Index.TOKENIZED, store = Store.NO) 122 private String scmConnection; 123 @Column(name = "GROUP_ID") 124 @Field(index = Index.TOKENIZED, store = Store.NO) 125 private String groupId; 126 @Column(name = "ARTIFACT_ID") 127 @Field(index = Index.TOKENIZED, store = Store.NO) 128 private String artifactId; 129 @Column(name = "VERSION") 130 @Field(index = Index.TOKENIZED, store = Store.NO) 131 private String version; 132 @ManyToOne 133 @JoinColumn(name = "OWNER_ID", nullable = false) 134 private User owner; 135 @ManyToOne 136 @JoinColumn(name = "POLICY_ID", nullable = false) 137 private Policy policy; 138 @Column(name = "MAIN_FLAG", nullable = false) 139 private Boolean mainLine = false; 140 @ManyToOne 141 @JoinColumn(name = "VIEW_ID") //, nullable = false) 142 143 private View view; 144 @ManyToOne 145 @JoinColumn(name = "PROJECT_ID") //, nullable = false) 146 147 private Project project; 148 @Column(name = "DESCRIPTION") 149 @Field(index = Index.TOKENIZED, store = Store.NO) 150 private String description; 151 152 public Integer getId() { 153 return this.id; 154 } 155 156 public String getName() { 157 return this.name; 158 } 159 160 public Date getCreated() { 161 return this.created; 162 } 163 164 public String getCreatedBy() { 165 return this.createdBy; 166 } 167 168 public Date getLastModified() { 169 return this.lastModified; 170 } 171 172 public String getLastModifiedBy() { 173 return this.lastModifiedBy; 174 } 175 176 public void setId(final Integer id) { 177 this.id = id; 178 } 179 180 public void setName(final String name) { 181 this.name = name; 182 } 183 184 public void setCreated(final Date created) { 185 this.created = created; 186 } 187 188 public void setCreatedBy(final String createdBy) { 189 this.createdBy = createdBy; 190 } 191 192 public void setLastModified(final Date lastModified) { 193 this.lastModified = lastModified; 194 } 195 196 public void setLastModifiedBy(final String lastModifiedBy) { 197 this.lastModifiedBy = lastModifiedBy; 198 } 199 200 public String getScmConnection() { 201 return this.scmConnection; 202 } 203 204 public String getGroupId() { 205 return this.groupId; 206 } 207 208 public String getArtifactId() { 209 return this.artifactId; 210 } 211 212 public String getVersion() { 213 return this.version; 214 } 215 216 public View getView() { 217 return this.view; 218 } 219 220 public Project getProject() { 221 return this.project; 222 } 223 224 public User getOwner() { 225 return this.owner; 226 } 227 228 public Policy getPolicy() { 229 return this.policy; 230 } 231 232 public boolean isMainLine() { 233 return mainLine; 234 } 235 236 public Boolean getMainLine() { 237 return mainLine; 238 } 239 240 public String getDescription() { 241 return this.description; 242 } 243 244 public void setScmConnection(final String scmConnection) { 245 this.scmConnection = scmConnection; 246 } 247 248 public void setGroupId(final String groupId) { 249 this.groupId = groupId; 250 } 251 252 public void setArtifactId(final String artifactId) { 253 this.artifactId = artifactId; 254 } 255 256 public void setVersion(final String version) { 257 this.version = version; 258 } 259 260 public void setView(final View view) { 261 this.view = view; 262 } 263 264 public void setProject(final Project project) { 265 this.project = project; 266 } 267 268 public void setOwner(final User owner) { 269 this.owner = owner; 270 } 271 272 public void setPolicy(final Policy policy) { 273 this.policy = policy; 274 } 275 276 public void setMainLine(final Boolean mainLine) { 277 this.mainLine = mainLine; 278 } 279 280 public void setDescription(final String description) { 281 this.description = description; 282 } 283 284 public boolean addDependency(final Dependency dep) { 285 dep.setCodeline(this); 286 287 return true; 288 } 289 290 public static Collection<Codeline> findAll() { 291 return JpaDao.getInstance().findAll(CLASS); 292 } 293 294 public static Collection<Codeline> findAllActive() { 295 Object[] params = { }; 296 297 return JpaDao.getInstance().findByNamedQuery(CLASS, QueryNames.CODELINES_ACTIVE, params); 298 } 299 300 public static Collection<Codeline> findRecentlyModified(final int daysAgo) { 301 Calendar cal = Calendar.getInstance(); 302 cal.add(Calendar.DATE, -daysAgo); 303 304 Object[] params = { 305 cal.getTime() 306 }; //XXX assert daysAgo is positive. 307 308 return JpaDao.getInstance().findByNamedQuery(CLASS, QueryNames.CODELINES_MODIFIED_SINCE_DATE, params); 309 } 310 311 public static Collection<Codeline> findByNameAndScmConnection(final String name, final String scmConnection) { 312 Object[] params = { 313 name, 314 scmConnection 315 }; 316 317 return JpaDao.getInstance().findByNamedQuery(CLASS, QueryNames.CODELINES_BY_NAME_AND_SCM_CONNECTION, params); 318 } 319 320 public Collection<Codeline> findAllConsumers(final boolean useVersion) { 321 if (useVersion) { 322 Object[] params = { 323 getGroupId(), 324 getArtifactId(), 325 getVersion() 326 }; 327 328 return JpaDao.getInstance().findByNamedQuery(CLASS, QueryNames.CODELINES_DEPENDENT_ON_ARTIFACT, params); 329 } else { 330 Object[] params = { 331 getGroupId(), 332 getArtifactId() 333 }; 334 335 return JpaDao.getInstance().findByNamedQuery(CLASS, QueryNames.CODELINES_DEPENDENT_ON_ARTIFACT_ANY_VERSION, params); 336 } 337 } 338 339 public void add() { 340 JpaDao.getInstance().add(this); 341 } 342 343 public void update() { 344 JpaDao.getInstance().update(this); 345 } 346 347 public void index() { 348 JpaDao.getInstance().index(this); 349 } 350 351 public void delete() { 352 TinLizard.getInstance().getScmDao().releaseFiles(this); 353 354 EntityManager em = JpaDao.getInstance().getEm(); 355 EntityTransaction tx = em.getTransaction(); 356 tx.begin(); 357 358 Class<?> clazz = CLASS; 359 Integer id = getId(); 360 361 try { 362 String clazzName; 363 int deleted; 364 365 // 366 clazzName = Dependency.class.getSimpleName(); 367 368 Query query = em.createQuery("delete from " + clazzName + " o where o.codeline.id = :id"); 369 query.setParameter("id", id); 370 deleted = query.executeUpdate(); 371 372 if (LOG.isDebugEnabled()) { 373 LOG.debug("Deleted " + deleted + " of type " + clazzName + "."); 374 } 375 376 // 377 clazzName = Codeline.class.getSimpleName(); 378 query = em.createQuery("delete from " + clazzName + " o where o.id = :id"); 379 query.setParameter("id", id); 380 deleted = query.executeUpdate(); 381 382 if (LOG.isDebugEnabled()) { 383 LOG.debug("Deleted " + deleted + " of type " + clazzName + "."); 384 } 385 386 // 387 em.refresh(project); 388 389 tx.commit(); 390 } catch (EntityNotFoundException e) { 391 JpaDao.getInstance().handleInfo(tx, ("Object " + clazz + "#" + id + " did not exist"), e); 392 } catch (Exception e) { 393 JpaDao.getInstance().handleError(tx, "Delete Error", e); 394 } 395 } 396 397 public void deleteAllDependencies() { 398 EntityManager em = JpaDao.getInstance().getEm(); 399 EntityTransaction tx = em.getTransaction(); 400 tx.begin(); 401 402 Integer id = getId(); 403 404 try { 405 String clazzName = Dependency.class.getSimpleName(); 406 407 Query query = em.createQuery("delete from " + clazzName + " o where o.codeline.id = :id"); 408 query.setParameter("id", id); 409 410 int deleted = query.executeUpdate(); 411 412 if (LOG.isDebugEnabled()) { 413 LOG.debug("Deleted " + deleted + " of type " + clazzName + "."); 414 } 415 416 tx.commit(); 417 } catch (Exception e) { 418 JpaDao.getInstance().handleError(tx, "Delete Error", e); 419 } 420 } 421 422 public Collection<Dependency> findAllDependencies() { 423 Object[] params = { 424 this 425 }; 426 427 return JpaDao.getInstance().findByNamedQuery(Dependency.class, QueryNames.DEPENDENCIES_BY_CODELINE, params); 428 } 429 430 public void refresh() { 431 TinLizard.getInstance().getScmDao().update(this); 432 updateFromPom(); 433 } 434 435 @SuppressWarnings("unchecked") 436 private void updateFromPom() { 437 Model pom = TinLizard.getInstance().getScmDao().getPOM(this); //XXX what about getEffectivePom(pb); ? 438 439 if (StringUtils.isNotBlank(pom.getGroupId())) { 440 setGroupId(pom.getGroupId()); 441 } else { 442 setGroupId(pom.getParent().getGroupId()); 443 } 444 445 setArtifactId(pom.getArtifactId()); 446 setVersion(pom.getVersion()); 447 448 deleteAllDependencies(); 449 450 Collection<org.apache.maven.model.Dependency> dependencies = pom.getDependencies(); 451 452 for (org.apache.maven.model.Dependency dependency : dependencies) { 453 Dependency dep = new Dependency(); 454 dep.setGroupId(dependency.getGroupId()); 455 dep.setArtifactId(dependency.getArtifactId()); 456 dep.setVersion(dependency.getVersion()); 457 dep.setClassifier(dependency.getClassifier()); 458 addDependency(dep); 459 dep.add(); 460 } 461 462 update(); 463 } 464 465 public Model getPOM() { 466 return TinLizard.getInstance().getScmDao().getPOM(this); 467 } 468 469 @SuppressWarnings("unchecked") 470 public static Collection<String> findAllGroupIds() { 471 EntityManager em = JpaDao.getInstance().getEm(); 472 EntityTransaction tx = em.getTransaction(); 473 tx.begin(); 474 475 Collection<String> groupIds = null; 476 477 try { 478 groupIds = new ArrayList<String>(); 479 480 Collection results = em.createQuery("select distinct o.groupId from Codeline o").getResultList(); 481 482 for (Iterator it = results.iterator(); it.hasNext();) { 483 Object obj = it.next(); 484 groupIds.add(obj.toString()); 485 } 486 487 tx.commit(); 488 } catch (Exception e) { 489 JpaDao.getInstance().handleError(tx, "Delete Error", e); 490 } 491 492 return groupIds; 493 } 494 495 @SuppressWarnings("unchecked") 496 public static Collection<String> findAllArtifactIds(final String groupId) { 497 EntityManager em = JpaDao.getInstance().getEm(); 498 EntityTransaction tx = em.getTransaction(); 499 tx.begin(); 500 501 Collection<String> artifactIds = null; 502 503 try { 504 artifactIds = new ArrayList<String>(); 505 506 Collection results = em.createQuery("select distinct o.artifactId from Codeline o where groupId = ?").setParameter(1, groupId).getResultList(); 507 508 for (Iterator it = results.iterator(); it.hasNext();) { 509 Object obj = it.next(); 510 artifactIds.add(obj.toString()); 511 } 512 513 tx.commit(); 514 } catch (Exception e) { 515 JpaDao.getInstance().handleError(tx, "Delete Error", e); 516 } 517 518 return artifactIds; 519 } 520 521 public static Collection<Codeline> search(final String query) { 522 String[] fields = { 523 "name", 524 "created", 525 "createdBy", 526 "lastModified", 527 "lastModifiedBy", 528 "scmConnection", 529 "groupId", 530 "artifactId", 531 "version" 532 }; 533 534 return JpaDao.getInstance().findByTextSearch(CLASS, query, fields); 535 } 536 537 public static void indexAll() { 538 JpaDao.getInstance().indexAll(CLASS); 539 } 540 }