/** * Copyright (c) 2011-2012, Thilo Planz. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package v7cr; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.bson.BSONObject; import org.bson.BasicBSONObject; import org.bson.types.ObjectId; import v7cr.v7db.AccountInfo; import v7cr.v7db.BSONBackedObject; import v7cr.v7db.BSONBackedObjectLoader; import v7cr.v7db.Role; import v7cr.v7db.SessionInfo; import v7cr.v7db.Versioning; import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; import com.mongodb.DBObject; import com.mongodb.WriteResult; import com.vaadin.Application; import com.vaadin.terminal.ExternalResource; import com.vaadin.terminal.ParameterHandler; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.URIHandler; import com.vaadin.terminal.VariableOwner; import com.vaadin.terminal.gwt.server.ChangeVariablesErrorEvent; import com.vaadin.terminal.gwt.server.HttpServletRequestListener; import com.vaadin.terminal.gwt.server.WebApplicationContext; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Link; import com.vaadin.ui.Window; import com.vaadin.ui.Window.Notification; /** * The Application's "main" class */ @SuppressWarnings("serial") public class V7CR extends Application implements HttpServletRequestListener { private static ThreadLocal<V7CR> currentApplication = new ThreadLocal<V7CR>(); private transient SessionInfo sessionInfo; private transient ResourceBundle messages; @Override public void init() { setLocale(Locale.JAPANESE); setMainWindow(new TopPageWindow(this)); } public void onRequestEnd(HttpServletRequest request, HttpServletResponse response) { currentApplication.remove(); sessionInfo = null; } public void onRequestStart(HttpServletRequest request, HttpServletResponse response) { sessionInfo = (SessionInfo) request.getSession().getAttribute( "v7cr.sessionInfo"); currentApplication.set(this); } static V7CR getInstance() { return currentApplication.get(); } AccountInfo getSessionUser() { return sessionInfo.accountInfo; } Map<String, Role> getRoles() { return sessionInfo.roles; } DBCollection getDBCollection(String name) { WebApplicationContext context = (WebApplicationContext) getContext(); return InitDB.getDBCollection(context.getHttpSession() .getServletContext(), name); } BSONBackedObject load(String collection, Object id) { return BSONBackedObjectLoader.findOne(getDBCollection(collection), id, null); } Object findId(String collection, DBObject criteria) { DBObject o = getDBCollection(collection).findOne(criteria, new BasicDBObject()); if (o == null) return null; return o.get("_id"); } List<BSONBackedObject> find(String collection) { List<BSONBackedObject> result = new ArrayList<BSONBackedObject>(); for (DBObject d : getDBCollection(collection).find()) { result.add(BSONBackedObjectLoader.wrap(d, null)); } return result; } WriteResult update(String collection, BSONBackedObject object) { return Versioning.update(getDBCollection(collection), Versioning .getVersion(object), object.getDBObject()); } WriteResult update(String collection, DBObject object) { return Versioning.update(getDBCollection(collection), Versioning .getVersion(object), object); } WriteResult insert(String collection, BSONBackedObject object) { return Versioning.insert(getDBCollection(collection), object .getDBObject()); } WriteResult insert(String collection, DBObject object) { return Versioning.insert(getDBCollection(collection), object); } BSONBackedObject storeFile(File file, String fileName, String mimeType) throws IOException { HttpClient http = new DefaultHttpClient(); HttpPut put = new HttpPut("http://0.0.0.0:8088/upload/v7cr"); put.setEntity(new FileEntity(file, mimeType)); HttpResponse response = http.execute(put); if (response.getStatusLine().getStatusCode() != 200) { throw new IOException("failed to save " + fileName + ": " + response.getStatusLine()); } String sha = IOUtils.toString(response.getEntity().getContent()); BSONObject r = new BasicBSONObject("sha", sha); r.put("filename", fileName); r.put("contentType", mimeType); r.put("length", file.length()); return BSONBackedObjectLoader.wrap(r, null); } Link getFile(BSONBackedObject file) { String fn = file.getStringField("filename"); String sha = file.getStringField("sha"); if (fn == null || sha == null) return null; URL url = getURL(); return new Link(fn, new ExternalResource(url.getProtocol() + "://" + url.getHost() + ":8088/upload/v7cr?filename=" + fn + "&sha=" + sha)); } @Override public Window getWindow(String name) { Window x = super.getWindow(name); if (x != null) return x; if (name.contains("-")) { String[] pjt_rev = StringUtils.split(name, '-'); // project name could contain spaces if (pjt_rev.length > 2) { pjt_rev = new String[] { StringUtils.join(pjt_rev, '-', 0, pjt_rev.length - 1), pjt_rev[pjt_rev.length - 1] }; } // check permission to access the project if (!getRoles().containsKey("project:" + pjt_rev[0])) { throw new SecurityException( "permission denied to access project " + pjt_rev[0]); } Object reviewId = findId("reviews", new BasicDBObject("p", pjt_rev[0]).append("svn.rev", Long.parseLong(pjt_rev[1]))); if (reviewId instanceof ObjectId) { Window reviewWindow = new Window(name); reviewWindow.addComponent(new ReviewTab((ObjectId) reviewId)); addWindow(reviewWindow); return reviewWindow; } throw new IllegalArgumentException(name); } return null; } String getMessage(String key) { if (messages == null) messages = ResourceBundle.getBundle("v7cr.messages", getLocale()); return messages.getString(key); } @Override public void terminalError(Terminal.ErrorEvent event) { if (event.getThrowable().getCause() instanceof ConcurrentModificationException) { // Finds the original source of the error/exception Object owner = null; if (event instanceof VariableOwner.ErrorEvent) { owner = ((VariableOwner.ErrorEvent) event).getVariableOwner(); } else if (event instanceof URIHandler.ErrorEvent) { owner = ((URIHandler.ErrorEvent) event).getURIHandler(); } else if (event instanceof ParameterHandler.ErrorEvent) { owner = ((ParameterHandler.ErrorEvent) event) .getParameterHandler(); } else if (event instanceof ChangeVariablesErrorEvent) { owner = ((ChangeVariablesErrorEvent) event).getComponent(); } // Shows the error in AbstractComponent if (owner instanceof AbstractComponent) { ((AbstractComponent) owner).getWindow().showNotification( getMessage("error.concurrentModification"), getMessage("error.concurrentModification.message"), Notification.TYPE_ERROR_MESSAGE); return; } } // Call the default implementation. super.terminalError(event); } }