很久很久以前

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  34 随笔 :: 4 文章 :: 17 评论 :: 0 Trackbacks

#

今天看到一个朋友的Blog, 就忍不住把以前写的这个代码拿出来了, 不然这代码闲着也是闲着. 当然没有必要照搬全部, 只要中间的那个 zoomImage() 方法即可. 当然还有设置图片部分透明的方法.

 

/*
* @(#)BlogMailHandler.java 1.00 2004-10-4
*
* Copyright 2004 . All rights reserved.
* PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.Properties;

import javax.imageio.ImageIO;
import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;

import studio.beansoft.jsp.StringUtil;
import com.keypoint.PngEncoder;
import com.keypoint.PngEncoderB;

import moblog.*;

/**
* BlogMailHandler, 彩E博客邮件的处理程序.
* 每 15 分钟更新一次邮件, 发布博客并更新用户产量.
* 邮件 POP3 帐户信息位于 /blogmail.properties 文件中.
*
* @author 刘长炯
* @version 1.00 2004-10-4
*/
public class BlogMailHandler extends Thread {
/**
* @alias 文件根目录 : String
*/
private String rootDirectory;

// 邮件帐户配置属性
private static Properties props = new Properties();

static {
try {
InputStream in = BlogMailHandler.class
.getResourceAsStream("/blogmail.properties");
props.load(in);
in.close();
} catch (Exception ex) {
System.err.println("无法加载配置文件 blogmail.properties:"
+ ex.getMessage());
ex.printStackTrace();
}
}

// 图像加载的共享实例, 在 Linux 平台上有可能无法生成图形对象
// private static Frame sharedFrame = new Frame();
private boolean shouldExit = false;

public BlogMailHandler() {
}
/** 定时开始读取邮件信息 */
public void startMailProcessCycle() {
start();
}
public void run() {
while(!shouldExit) {
doProcess();
try {
// 每15分钟读取一次
Thread.currentThread().sleep(60 * 15 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** 处理进程 */
private void doProcess() {
try {
Store store = openStore();
Folder inbox = openInbox(store);

processAllMessages(inbox);
inbox.close(true);
store.close();
} catch (Exception e) {
e.printStackTrace();
}
}
protected void finalize() throws Throwable {
shouldExit = true;
}
/**
* 缩放原始图片到合适大小.
*
* @param srcImage - 原始图片
* @return BufferedImage - 处理结果
*/
private BufferedImage zoomImage(BufferedImage srcImage) {
int MAX_WIDTH = 100;// TODO: 缩放后的图片最大宽度
int MAX_HEIGHT = 160;// TODO: 缩放后的图片最大高度
int imageWidth = srcImage.getWidth(null);
int imageHeight = srcImage.getHeight(null);

// determine thumbnail size from MAX_WIDTH and MAX_HEIGHT
int thumbWidth = MAX_WIDTH;
int thumbHeight = MAX_HEIGHT;
double thumbRatio = (double)thumbWidth / (double)thumbHeight;
double imageRatio = (double)imageWidth / (double)imageHeight;
if (thumbRatio < imageRatio) {
thumbHeight = (int)(thumbWidth / imageRatio);
} else {
thumbWidth = (int)(thumbHeight * imageRatio);
}
// 如果图片小于所略图大小, 不作处理
if(imageWidth < MAX_WIDTH && imageHeight < MAX_HEIGHT) {
thumbWidth = imageWidth;
thumbHeight = imageHeight;
}

// draw original image to thumbnail image object and
// scale it to the new size on-the-fly (drawImage is quite powerful)
BufferedImage thumbImage = new BufferedImage(thumbWidth,
thumbHeight, BufferedImage.TYPE_INT_RGB);
//thumbImage.getsc
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(srcImage, 0, 0, thumbWidth, thumbHeight, null);
System.out.println("thumbWidth=" + thumbWidth);
System.out.println("thumbHeight=" + thumbHeight);
return thumbImage;
}

// Open mail Store
private Store openStore() throws Exception {
Store store;
//--[ Set up the default parameters
props.put("mail.transport.protocol", "pop");
props.put("mail.pop.port", "110");
// props.put("mail.debug", "true");

Session session = Session.getInstance(props);
store = session.getStore("pop3");
// void javax.mail.Service.connect(String host, String user, String
// password) throws
// MessagingException
store.connect(props.getProperty("mail.pop3.host"), props
.getProperty("username"), props.getProperty("password"));
return store;
}

// Open Inbox
private Folder openInbox(Store store) throws Exception {
Folder folder = store.getDefaultFolder();
if (folder == null) {
System.out.println("Problem occurred");
System.exit(1);
}

Folder popFolder = folder.getFolder("INBOX");
popFolder.open(Folder.READ_WRITE);
return popFolder;
}

/** Close mail store. */
private void closeStore(Store store) {
try {
store.close();
} catch (MessagingException e) {
e.printStackTrace();
}
}

/**
* 处理账号中的所有邮件并删除这些邮件.
*
* @param folder - Folder, 收件箱
* @throws Exception
*/
private void processAllMessages(Folder folder) throws Exception {

Message[] listOfMessages = folder.getMessages();
FetchProfile fProfile = new FetchProfile();
fProfile.add(FetchProfile.Item.ENVELOPE);
folder.fetch(listOfMessages, fProfile);

for (int i = 0; i < listOfMessages.length; i++) {
try {
processSingleMail(listOfMessages[i]);
} catch (Exception e) {
e.printStackTrace();
}

// Delete mail
listOfMessages[i].setFlag(Flags.Flag.DELETED, true);
}
}

/**
* 处理单个 Email, 将文章发表, 并将附件图片转换为 PNG 后存入用户目录.
*
* @param message -
* Message, email 消息
*/
private void processSingleMail(Message message) throws Exception {
BlogContent content = new BlogContent();
BlogUser user = new BlogUser();
BlogPicture picture = new BlogPicture();

// 1. 假定发件人为手机号, 并尝试根据手机号查找用户
Address[] addList = message.getFrom();
if (addList.length > 0) {
String userMail = ((InternetAddress) addList[0]).getAddress();
// 取出 彩E 邮件用户手机号, 格式: 手机号@someone.com
String mobileNumber = userMail.substring(0, userMail.indexOf("@"));
System.out.println("用户手机号为:" + mobileNumber);
if (!user.findByMDN(mobileNumber)) {
// Not found user, then return
System.err.println("user " + ((InternetAddress) addList[0]).getAddress() + " not found.");
return;
}
}

// 2. 尝试读取邮件正文
// 复合邮件
if (message.isMimeType("multipart/*")) {
// 标记是否处理过图片
boolean imageHasProcessed = false;
Multipart multipart = (Multipart) message.getContent();
for (int i = 0, n = multipart.getCount(); i < n; i++) {
// System.err.println("Reading multipart " + i);
Part part = multipart.getBodyPart(i);
// System.err.println("ContentType = " + part.getContentType());

// 3. 处理附件图片, 只处理第一个图片
String disposition = part.getDisposition();
// System.err.println("disposition = " + disposition);
if (disposition != null
&& (disposition.equals(Part.ATTACHMENT) || disposition
.equals(Part.INLINE)) && !imageHasProcessed) {
// 需要反编码邮件文件名, 有的邮件的附件的文件名是经过编码的,
// 但是 JavaMail 并不能处理出来(BeanSoft, 2004-10-13)
String fileName = MimeUtility.decodeText(part.getFileName());
String ext = StringUtil.getExtension(fileName)
.toLowerCase();
System.err.println("part.getFileName() = " + fileName);

if ("gif".equals(ext) || "jpg".equals(ext)
|| "png".equals(ext)) {
BufferedInputStream dataIn = null;
// 转换非 PNG 格式图片为 PNG 格式 -- 取消
// if (!"png".equals(ext)) {
ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
try {
// Convert image file to PNG file
BufferedImage buffImg = ImageIO.read(part
.getInputStream());
// Read image file from attachment
// 缩放图片
buffImg = zoomImage(buffImg);

int imageWidth = buffImg.getWidth(null);
int imageHeight = buffImg.getHeight(null);
BufferedImage outImg = new BufferedImage(
imageWidth, imageHeight,
// BufferedImage.TYPE_4BYTE_ABGR 是 24 位色深, TYPE_BYTE_INDEXED 是 8 位
BufferedImage.TYPE_INT_RGB);
// 使图片透明
// embossImage(buffImg, outImg);
outImg.getGraphics().drawImage(buffImg, 0, 0, imageWidth, imageHeight, null);
// Save image to PNG output stream
// ImageIO.write(outImg, "png", pngOut);
// Save using keypoint PNG encoder
PngEncoderB pngb = new PngEncoderB(outImg,
PngEncoder.NO_ALPHA, 0, 9);
pngOut.write(pngb.pngEncode());
dataIn = new BufferedInputStream(
new ByteArrayInputStream(pngOut
.toByteArray()));
} catch (Exception e) {
}
// } else {
// dataIn = new BufferedInputStream(part
// .getInputStream());
// }
// All pictures change to png format
ext = "png"
// Insert picture info into database
picture.setBlogID(user.getId());
picture.setCreationTime(new Timestamp(System
.currentTimeMillis()));
picture.setFileEXName(ext);
picture.setTitle(fileName);
picture.create();
// Save png file to user directory, /users/userId/pictureId.png
FileOutputStream outFile = new FileOutputStream(
rootDirectory + File.separatorChar + user.getId() + File.separatorChar
+ picture.getId() + "." + ext);
int c;
while ((c = dataIn.read()) != -1) {
outFile.write(c);
}

outFile.close();
imageHasProcessed = true;
}
}
// 纯文本邮件, 带附件
else if (part.isMimeType("text/plain")) {
String body = part.getContent().toString();
String title = message.getSubject();

content.setBlogID(user.getId());
content.setCreationTime(new Timestamp(System.currentTimeMillis()));
content.setTitle(title);
content.setNote(body);
}

// 典型的 HTML 和 文本邮件可选形式, 进一步分析
if (part.getContent() instanceof Multipart) {
Multipart subPart = (Multipart) part.getContent();

for (int j = 0, m = subPart.getCount(); j < m; j++) {
Part mailText = subPart.getBodyPart(j);

if (mailText.isMimeType("text/plain")) {
String body = mailText.getContent().toString();
String title = message.getSubject();

content.setBlogID(user.getId());
content.setCreationTime(new Timestamp(System.currentTimeMillis()));
content.setTitle(title);
content.setNote(body);
break;
}
}
}

}// End of multipart parse

// 4. 创建博客记录
content.setPictureId(picture.getId());
if(content.create() > 0) {
// 更新用户产量
user.setPostTimes(user.getPostTimes() + 1);
user.update();
}
}
// 纯文本邮件, 无附件
else if (message.isMimeType("text/plain")) {
String body = message.getContent().toString();
String title = message.getSubject();

content.setBlogID(user.getId());
content.setCreationTime(new Timestamp(System.currentTimeMillis()));
content.setTitle(title);
content.setNote(body);

if(content.create() > 0) {
// 更新用户产量
user.setPostTimes(user.getPostTimes() + 1);
user.update();
}
}
}

// 测试, 尝试连接一次到邮件服务器
public static void main(String[] args) {
BlogMailHandler handler = new BlogMailHandler();

// TODO: debug, 请在 JSP 里面设置图片目录的根路径
handler.rootDirectory = "F:/Moblog/users/"
handler.doProcess();
}

/**
* @return Returns the rootDirectory.
*/
public String getRootDirectory() {
return rootDirectory;
}

/**
* @param rootDirectory
* The rootDirectory to set.
*/
public void setRootDirectory(String property1) {
this.rootDirectory = property1;
}

/** Make image transparent */
private void embossImage(BufferedImage srcImage, BufferedImage destImage) {
int width = srcImage.getWidth();
int height = srcImage.getHeight();

for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int newColor = handlesinglepixel(j, i, srcImage.getRGB(j, i));
destImage.setRGB(j, i, newColor);
}
}
}

// Handle picture single pixel, change 0xff00ff color to transparent
private int handlesinglepixel(int x, int y, int pixel) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
// Deal with the pixel as necessary...
// alpha 为 0 时完全透明, 为 255 时不透明
Color back = new Color(0xFF00FF);
// 将与背景色相同(此处PNG图片为紫色)的像素点的透明度设为透明
if (isDeltaInRange(back.getRed(), red, 2)
&& isDeltaInRange(back.getGreen(), green, 2)
&& isDeltaInRange(back.getBlue(), blue, 2)) {
// System.out.println("x=" + x + "y=" + y + " is transparent.");
alpha = 0;
}
// red = red / 2;
// //green = green / 2 + 68;
// blue = blue / 2;

return alpha << 24 | red << 16 | green << 8 | blue;
}

// 判断两个整数的差是否在一定范围之内
private boolean isDeltaInRange(int first, int second, int range) {
if (first - second <= range && second - first <= range)
return true;
return false;
}
}

  • # re: Java 中收取邮件并自动缩放图片的代码(原创)
    冷面阎罗
    Posted @ 2006-12-29 18:31
    不错!
    自己也写过java收发邮件的程序!  回复  
  • # re: Java 中收取邮件并自动缩放图片的代码(原创)
    托托姆
    Posted @ 2006-12-30 12:10
    不知道BeanSoft兄是不是看了我昨天的帖子有此感想。。。:)
    我测试了一下BeanSoft兄的zoomImage() 方法,如果按原代码执行,原本图片透明的部分将变成黑色。如果修改TYPE_INT_RGB为TYPE_INT_ARGB,则能避免这个问题。
posted @ 2006-12-30 13:27 Long Long Ago 阅读(569) | 评论 (0)编辑 收藏

写程序中遇到一个问题 如下:
mySoc = new Socket(svrAddress,5555);


myInput = new ObjectInputStream(mySoc.getInputStream());//有问题
myOutput = new ObjectOutputStream(mySoc.getOutputStream());//有问题
//myInput = new DataInputStream(mySoc.getInputStream());
//myOutput = new DataOutputStream(mySoc.getOutputStream()); 
注销的语句运行可以成功
但是未注销的那部分 运行时就卡在那里了
但是却没有抛出异常
请教原因是什么 有什么问题
该怎么解决呢?

找了好久终于再网上找到关于这个问题的说明了 因为问题比较特殊 所以贴出来希望对大家
有帮助

主机端先建立ObjectInputStream后建立ObjectOutputStream,则对应地客户端要先建立
ObjectOutputStream后建立ObjectInputStream,否则会造成两方互相等待数据而导致死
锁。

原因是建立ObjectInputStream对象是需要先接收一定的header数据,接收到这些数据之前
会处于阻塞状态。故而为了防止这种死锁状态,通讯两方的
ObjectInputStraem,ObjectOutputStream必须注意顺序对应使用。


目前相应的解决办法还没有找到 如果要解决 可以尝试重载对象输入输出流
posted @ 2006-12-30 12:46 Long Long Ago 阅读(927) | 评论 (1)编辑 收藏

       Tabbed Property是eclipse3.2中新加入一个view,可以使属性编辑器的功能近乎无限的扩大。这里说明一些Tabbed Property的使用方法。Tabbed Property中分成三个部分,Contributer,Tabs,Sections,一个Contributor包含若干个Tabs,一个Tabs又可以包含若干个sections。下面我们来分别进行描述。
      1。Contributor 这需要扩展org.eclipse.ui.views.properties.tabbed.PropertyContributor扩展点,定义时,最重要的是定义contributId,这个id必须是全局唯一的,这样在加载属性页时,才能找到这个我们定义的属性页,一般地,我们都将对应于这个属性页的workbenchpart的id作为本contributor的id,这样我们在代码中可以不硬编码本id字符串,而使用getSite().getId()就可以得到这个id了(当然,这样定义id不是必须的)。一个property view可以被多个workbench part共享,但 一个workbench part只能有一个property view,这个workbench part需要实现ITabbedPropertySheetPageContributor 接口,这个接口只有一个方法,要求返回本part对应的tabbed property Contributor id,一般只要return getSite().getId();
   contributor有如下几个attribute:
   1)typeMapper,这个类需要实现org.eclipse.ui.views.properties.tabbed.ITypeMapper,主要是实现类型的映射,因为我们选择的元素并不一定是实现IPropertySource的元素(即能够给property view提供内容的元素),比如在GEF中,我们选择的finger实际上是选择了对应的EditPart,而实际上实现了IPropertySource一般的是model部分的元素,所以这时候我们要将Editpart映射到对应的model元素。
   2)labelProvider,需要一个实现org.eclipse.jface.viewers.ILabelProvider的类,主要是在各个tabs的最上面显示文字和图片。
   3)propertyCategory,用于聚合多个tabs,注意至少要定义一个category,来聚合tabs,否则,可能会显示property失败。

   2。Tabs,这个需要扩展org.eclipse.ui.views.properties.tabbed.propertyTabs扩展点,其中contributorId就是与之相关联的Contributor的id,然后我们可以定义多个tab,这些tab的属性如下:
   1)label,用于显示在property view的tab bar上的字
   2)category,填入的就是在Contributor扩展点中定义的那些category,用于聚合tabs
   3)id,本tab的唯一标识
   4)afterTab,用于tab之间的排序,如果这是第一个tab,则没有afterTab,afterTab指的是在本tab之前的那个tab,并且afterTab描述的是在同一个category中的tabs,不同category之间的顺序是按照在contributor中定义category的顺序来定义的。
   5)indented,如果为ture,则各个tabs是有缩进的
   6)image,本tab的图片

   3。section ,需要扩展 org.eclipse.ui.views.properties.tabbed.PropertySections扩展点,它的contributionId就是本section所在的Contribution的id,针对每个tab,我们可以定义多个section,每个section的attribut描述如下:
   1)id,本secation的唯一标识
   2)tab,本section所属tab的标识
   3)class,实现了org.eclipse.ui.views.properties.tabbed.AbstractPropertySection抽象类的类,用于描述这个section的控件和布局。
   4)aftersection和上面的aftertab差不多,描述的是同一个tab中的section的顺序,注意afterserction描述的是本section之前的section的id
   5)filter:一个实现org.eclipse.jface.viewers.IFilter接口的过滤器,对选中元素进行过滤。
   6)enableFor:一个用于只是选择数目的值,必须要符合这个舒服才能使能这个section。如果不符合,则这个section就被过滤了,如果省略本值,则section的使能器就不会工作了。这是一个自然数,比如,当enableFor=1时,仅仅只有一个元素被选择的时候,本section才会被使能。

some notes:
    上面说过实现ITabbedPropertySheetPageContributor接口的workbench part除了要实现getContributeId方法外,还需要重载getAdapter方法,因为eclipse的默认加载的property veiw时原来的那个view,为了使tabbed property view能够加载,我们就需要重载getAdapter方法,返回一个TabbedPropertySheetPage对象。

    在实现section class的时候需要注意,createcontrol时首先应该先创建一个composite,一般是 Composite composite = getWidgetFactory().createFlatFormComposite(parent); 然后各个控件在这个composite上创建。


posted @ 2006-09-17 22:24 Long Long Ago 阅读(2851) | 评论 (1)编辑 收藏

安装subversion
基本命令:
  $ sudo apt-get install subversion
  $ sudo apt-get install libapache2-svn
可以安装的包:
 apache2
 apache2-common
 apache2-mpm-prefork
 apache2-utils
 libapache2-svn
 libapache2-mod-auth-pam
 libapache2-mod-auth-sys-group
 subversion
 subversion-tools


创建一个名为subversion的组:groupadd subversion
将自己(eg.:user)和www-data(apapch2帐号)用户添加入subversion组,可以编辑/etc/group文件,在最后找到subversion添加入帐号名(eg:user,www-data),看上去就像这样:subversion:x:1001:www-data,exp
然后是创建subversion库,并赋予subversion组中用户有读写subversion库的权限:
   $ sudo mkdir /home/svn  #创建svn库的父路径
   $ cd /home/svn
   $ sudo mkdir myproject  #创建本svn库的目录
   $ sudo svnadmin create /home/svn/myproject #使用svn命令,创建svn库
   $ sudo chown -R root:subversion myproject #更改本目录的组
   $ sudo chmod -R g+rws myproject #给本目录的组用户增加读写和递归增加新加目录的读写权限
注意上面提到的命令顺序,如果最后再执行创建库的命令(svnadmin create ....)则创建的文件没有获得组用户写的权限,这样在外部访问提交的时候会出错.
对于本机,可以直接使用file命令来访问:
  $ svn co(or checkout) file:///home/svn/myproject
#or
  $ svn co file://localhost/home/svn/myproject
注意:如果您并不确定主机的名称,您必须使用三个斜杠(///),而如果您指定了主机的名称,则您必须使用两个斜杠(//).
此时对svn库的权限是基于文件系统的,只要是subversion组中的用户都可以访问本svn库。

接下来,讲述如何使用apache服务器来提供对svn库的访问
编辑文件/etc/apache2/mods-available/dav_svn.conf
增加如下的内容:
  <Location /svn/myproject>
     DAV svn
     SVNPath /home/svn/myproject
     AuthType Basic
     AuthName "myproject subversion repository"
     AuthUserFile /etc/subversion/passwd
     
<LimitExcept GET PROPFIND OPTIONS REPORT>
        Require valid-user
     
</LimitExcept>
  
</Location>

apache会解析url中的/svn/myproject部分,来定位svn库,当收到此请求时,会查询svn库:/home/svn/myproject,这里的认证方式是basic,对于访问要求valid-user,帐号文件在/etc/subversion/passwd中。
注意重新设置后要重启apache2:sudo /etc/init.d/apache2 restart
编辑生成帐号文件: sudo htpasswd2 -c /etc/subversion/passwd user  #给user帐号创建口令
这时候可以通过浏览器来浏览svn库了
在我的设置中发现,apache2会自动绑定ipv6地址,可能会有些问题,可以强制apache绑定v4地址,在/etc/apache2/port.conf中改成:Listen [bindedip]:[port]的形式

通过https来访问svn库
首先生成一个 SSL 签名,使用命令

 # apache2-ssl-certificate

这里会有一系列关于你的个人隐私的问题,回答完了,自然的签名也就生成了,然
后我们就要在 apache2 里面打开 SSL 了,现在要做的是开启 ssl 模块

 # a2enmod ssl

然后,使用 apache2 的虚拟主机功能来添加 SSL 的支持,将

 /etc/apache2/sites-available/default

复制一份,叫

 /etc/apache2/sites-available/ssl

好啦

修改 default 文件的开头为

 NameVirtualHost *:80
 <VirtualHost *:80>

修改 ssl 文件的开头为

 NameVirtualHost *:443
 <VirtualHost *:443>

这里 443 是 SSL 的标准端口。

并在 ssl 文件中加入如下内容,在<VirtualHost></VirtualHost>内

 SSLEngine On
 SSLCertificateFile /etc/apache2/ssl/apache.pem

保存文件后,运行命令

   # a2ensite ssl

来激活这个虚拟主机

现在,修改文件

 /etc/apache2/ports.conf

加上一行

 Listen 443

好了,到此为止,SSL 服务器配置完成,重新启动 apache 吧。

 

一些问题:
可能出现 RA layer request failed svn: MKACTIVITY of 400 Bad Request 之类的错误,这可能是因为使用了代理的原因,代理不支持svn的扩展命令,see:http://subversion.tigris.org/faq.html#proxy
还有种原因,就是可能是你的客户端使用的是windowsxp,其他版本的windows我没试过,也是这样的错误,在linux下正常,解决方法不太清楚。
RA layer request failed svn: MKACTIVITY of 400 Bad Request,无论什么原因都可以用https代替http来暂时解决这样的问题。

参考:
http://fanqiang.chinaunix.net/app/web/2005-05-18/3257.shtml
http://wiki.ubuntu.org.cn/SubVersion?highlight=%28subversion%29

posted @ 2006-09-05 17:00 Long Long Ago 阅读(2948) | 评论 (0)编辑 收藏

在sources.list中添加如下几个源:
deb http://www.beerorkid.com/compiz/ dapper main
deb http://xgl.compiz.info/ dapper main
deb-src http://xgl.compiz.info/ dapper main
添加代理:
export http_proxy="http://xxx.xxx.xxx.xxx:xxxx"
获取pgp密钥:
wget http://www.beerorkid.com/compiz/quinn.key.asc -O - | sudo apt-key add - 

nivida的驱动:
sudo apt-get install nvidia-kernel-common nvidia-glx
编辑文件:/etc/X11/xorg.conf
在module部分中确定lode xgl,有如下代码:
Load "glx"
在devices部分修改除了Identifier行的其他各行,修改后如下:
Section "Device"
    Identifier- leave this line alone!
    Driver        "nvidia"
    BusID        "PCI:1:0:0"
    Option         "RenderAccel"         "true"
EndSection
在最下面添加Extensions部分,代码如下:
Section "Extensions"
          Option  "Composite" "Enable"
EndSection
下面是安装必要的库文件:
sudo apt-get install compiz xserver-xgl libgl1-mesa xserver-xorg libglitz-glx1 compiz-gnome
以上是引文http://www.ubuntuforums.org/showthread.php?t=131267 中的方法,此文所讲的后面是加载方法,我没有采用,用的是这里讲的方法:http://forum.ubuntu.org.cn/viewtopic.php?t=16777 不过这里讲的安装方法中少了一个库文件,呵呵
设置xgl启动入口:
新建一个xgl启动脚本/usr/bin/startxgl.sh,内容如下:
Xgl -fullscreen :1 -ac -accel glx:pbuffer -accel xv:pbuffer & sleep 2 && DISPLAY=:1
# Start GNOME
exec gnome-session 
使脚本可执行: sudo chmod 755 /usr/bin/startxgl.sh
新建一个compiz脚本/usr/bin/startcompiz,内容如下:
#!/bin/sh
killall gnome-window-decorator
wait
gnome-window-decorator & LD_PRELOAD=/usr/lib/fglrx/libGL.so.1.2.xlibmesa
compiz --replace gconf miniwin decoration transset wobbly fade minimize cube rotate zoom scale move resize place switcher trailfocus water & 
使得脚本可执行:sudo chmod 755 /usr/bin/startcompiz
在登陆管理器里建一个XGL会话: 建立一个文件/usr/share/xsessions/xgl.desktop ,内容如下:
[Desktop Entry]
Encoding=UTF-8
Name=XGl
Exec=/usr/bin/startxgl.sh
Icon=
Type=Application 

打开桌面菜单-〉系统-〉首选项-〉会话
在最右边的“启动程序”里添加 /usr/bin/startcompiz 这句话
最后不要忘了

sudo aptitude update
sudo aptitude upgrade
关闭所有程序
ctrl-alt-backspace启动X
登录时在会话中选择xgl
会提示是否为默认会话,建议选择仅本次
哦,差点忘了,怎么使用:
CTRL + ALT + Left/right arrow key. Switches to the new side of the cube for me.

CTRL + ALT + SHIFT + Left/Right arrow key- Takes the in focused app around cube.

CTRL + ALT + Left Click on Desktop - allows you to use the mouse to rotate cube.

F12 - uses the Expose like trick

Alt- Tab - switcher Vista-style
看起来有点晕,尤其是输入法的浮动窗体
posted @ 2006-08-31 13:03 Long Long Ago 阅读(888) | 评论 (3)编辑 收藏

java.lang.NoClassDefFoundError: com/sun/tools/javac/Main
最近在使用java的动态编译的时候出现的问题,主要是由于在使用类com.sun.tool.javac.Main时,总是出现NoClassDefFoundError的错误,后来找到如下的文章,分析,可能是由于对于包tools.jar的加载问题,虽然我在classpath中声明了这个包,但在eclipse环境下,始终都还是出现运行时异常,对于编译时正确,运行时异常的情况,eclipse一般都是由于其自身的加载机制造成的.在eclipse下,对于一般的java工程,只要设置了系统的classpath,在其中添加了tools.jar包,即可;对于plugin工程,我是将tools.jar包,直接拷贝到本工程下,并在property中引用,而且在META-INF/MANIFEST.MF文件中的Runtime页的classpath中添加了这个tool.jar包,这样在运行时就没有异常了,可以正常编译了.

理解Java ClassLoader机制

Java ClassLoader

2006-5-23
当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构:

       bootstrap classloader
                |
       extension classloader
                |
       system classloader

bootstrap classloader -引导(也称为原始)类加载器,它负责加载Java的核心类。在Sun的JVM中,在执行java的命令中使用-Xbootclasspath选项或使用- D选项指定sun.boot.class.path系统属性值可以指定附加的类。这个加载器的是非常特殊的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM自身实现的。大家可以通过执行以下代码来获得bootstrap classloader加载了那些核心类库:
   URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
   for (int i = 0; i < urls.length; i++) {
     System.out.println(urls.toExternalform());
   }
在我的计算机上的结果为:
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/dom.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/sax.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xalan-2.3.1.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xercesImpl-2.0.0.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xml-apis.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/endorsed/xsltc.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/i18n.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/sunrsasign.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/jsse.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/jce.jar
文件:/C:/j2sdk1.4.1_01/jre/lib/charsets.jar
文件:/C:/j2sdk1.4.1_01/jre/classes
这时大家知道了为什么我们不需要在系统属性CLASSPATH中指定这些类库了吧,因为JVM在启动的时候就自动加载它们了。

extension classloader -扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。这为引入除Java核心类以外的新功能提供了一个标准机制。因为默认的扩展目录对所有从同一个JRE中启动的JVM都是通用的,所以放入这个目录的 JAR类包对所有的JVM和system classloader都是可见的。在这个实例上调用方法getParent()总是返回空值null,因为引导加载器bootstrap classloader不是一个真正的ClassLoader实例。所以当大家执行以下代码时:
   System.out.println(System.getProperty("java.ext.dirs"));
   ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
   System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
结果为:
C:\j2sdk1.4.1_01\jre\lib\ext
the parent of extension classloader : null
extension classloader是system classloader的parent,而bootstrap classloader是extension classloader的parent,但它不是一个实际的classloader,所以为null。

system classloader -系统(也称为应用)类加载器,它负责在JVM被启动时,加载来自在命令java中的-classpath或者java.class.path系统属性或者 CLASSPATH操作系统属性所指定的JAR类包和类路径。总能通过静态方法ClassLoader.getSystemClassLoader()找到该类加载器。如果没有特别指定,则用户自定义的任何类加载器都将该类加载器作为它的父加载器。执行以下代码即可获得:
   System.out.println(System.getProperty("java.class.path"));
输出结果则为用户在系统属性里面设置的CLASSPATH。
classloader 加载类用的是全盘负责委托机制。所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入;委托机制则是先让parent(父)类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。


每个ClassLoader加载Class的过程是:
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4
3.请求parent classloader载入,如果成功到8,不成功到5
4.请求jvm从bootstrap classloader中载入,如果成功到8
5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.
6.从文件中载入Class,到8.
7.抛出ClassNotFoundException.
8.返回Class.

其中5.6步我们可以通过覆盖ClassLoader的findClass方法来实现自己的载入策略。甚至覆盖loadClass方法来实现自己的载入过程。

类加载器的顺序是:
先是bootstrap classloader,然后是extension classloader,最后才是system classloader。大家会发现加载的Class越是重要的越在靠前面。这样做的原因是出于安全性的考虑,试想如果system classloader“亲自”加载了一个具有破坏性的“java.lang.System”类的后果吧。这种委托机制保证了用户即使具有一个这样的类,也把它加入到了类路径中,但是它永远不会被载入,因为这个类总是由bootstrap classloader来加载的。大家可以执行一下以下的代码:
   System.out.println(System.class.getClassLoader());
将会看到结果是null,这就表明java.lang.System是由bootstrap classloader加载的,因为bootstrap classloader不是一个真正的ClassLoader实例,而是由JVM实现的,正如前面已经说过的。

下面就让我们来看看JVM是如何来为我们来建立类加载器的结构的:
sun.misc.Launcher,顾名思义,当你执行java命令的时候,JVM会先使用bootstrap classloader载入并初始化一个Launcher,执行下来代码:
  System.out.println("the Launcher's classloader is "+sun.misc.Launcher.getLauncher().getClass().getClassLoader());
结果为:
  the Launcher's classloader is null (因为是用bootstrap classloader加载,所以class loader为null)
Launcher 会根据系统和命令设定初始化好class loader结构,JVM就用它来获得extension classloader和system classloader,并载入所有的需要载入的Class,最后执行java命令指定的带有静态的main方法的Class。extension classloader实际上是sun.misc.Launcher$ExtClassLoader类的一个实例,system classloader实际上是sun.misc.Launcher$AppClassLoader类的一个实例。并且都是 java.net.URLClassLoader的子类。

让我们来看看Launcher初试化的过程的部分代码。

Launcher的部分代码:
public class Launcher  {
   public Launcher() {
       ExtClassLoader extclassloader;
       try {
           //初始化extension classloader
           extclassloader = ExtClassLoader.getExtClassLoader();
       } catch(IOException ioexception) {
           throw new InternalError("Could not create extension class loader");
       }
       try {
           //初始化system classloader,parent是extension classloader
           loader = AppClassLoader.getAppClassLoader(extclassloader);
       } catch(IOException ioexception1) {
           throw new InternalError("Could not create application class loader");
       }
       //将system classloader设置成当前线程的context classloader(将在后面加以介绍)
       Thread.currentThread().setContextClassLoader(loader);
       ......
   }
   public ClassLoader getClassLoader() {
       //返回system classloader
       return loader;
   }
}

extension classloader的部分代码:
static class Launcher$ExtClassLoader extends URLClassLoader {

   public static Launcher$ExtClassLoader getExtClassLoader()
       throws IOException
   {
       File afile[] = getExtDirs();
       return (Launcher$ExtClassLoader)AccessController.doPrivileged(new Launcher$1(afile));
   }
  private static File[] getExtDirs() {
       //获得系统属性“java.ext.dirs”
       String s = System.getProperty("java.ext.dirs");
       File afile[];
       if(s != null) {
           StringTokenizer stringtokenizer = new StringTokenizer(s, File.pathSeparator);
           int i = stringtokenizer.countTokens();
           afile = new File;
           for(int j = 0; j < i; j++)
               afile[j] = new File(stringtokenizer.nextToken());

       } else {
           afile = new File[0];
       }
       return afile;
   }
}

system classloader的部分代码:
static class Launcher$AppClassLoader extends URLClassLoader
{

   public static ClassLoader getAppClassLoader(ClassLoader classloader)
       throws IOException
   {
       //获得系统属性“java.class.path”
       String s = System.getProperty("java.class.path");
       File afile[] = s != null ? Launcher.access$200(s) : new File[0];
       return (Launcher$AppClassLoader)AccessController.doPrivileged(new Launcher$2(s, afile, classloader));
   }
}

看了源代码大家就清楚了吧,extension classloader是使用系统属性“java.ext.dirs”设置类搜索路径的,并且没有parent。system classloader是使用系统属性“java.class.path”设置类搜索路径的,并且有一个parent classloader。Launcher初始化extension classloader,system classloader,并将system classloader设置成为context classloader,但是仅仅返回system classloader给JVM。

  这里怎么又出来一个context classloader呢?它有什么用呢?我们在建立一个线程Thread的时候,可以为这个线程通过setContextClassLoader方法来指定一个合适的classloader作为这个线程的context classloader,当此线程运行的时候,我们可以通过getContextClassLoader方法来获得此context classloader,就可以用它来载入我们所需要的Class。默认的是system classloader。利用这个特性,我们可以“打破”classloader委托机制了,父classloader可以获得当前线程的context classloader,而这个context classloader可以是它的子classloader或者其他的classloader,那么父classloader就可以从其获得所需的 Class,这就打破了只能向父classloader请求的限制了。这个机制可以满足当我们的classpath是在运行时才确定,并由定制的 classloader加载的时候,由system classloader(即在jvm classpath中)加载的class可以通过context classloader获得定制的classloader并加载入特定的class(通常是抽象类和接口,定制的classloader中是其实现),例如web应用中的servlet就是用这种机制加载的.


好了,现在我们了解了classloader的结构和工作原理,那么我们如何实现在运行时的动态载入和更新呢?只要我们能够动态改变类搜索路径和清除classloader的cache中已经载入的Class就行了,有两个方案,一是我们继承一个classloader,覆盖loadclass方法,动态的寻找Class文件并使用defineClass方法来;另一个则非常简单实用,只要重新使用一个新的类搜索路径来new一个classloader就行了,这样即更新了类搜索路径以便来载入新的Class,也重新生成了一个空白的cache(当然,类搜索路径不一定必须更改)。噢,太好了,我们几乎不用做什么工作,java.netURLClassLoader正是一个符合我们要求的classloader!我们可以直接使用或者继承它就可以了!

这是j2se1.4 API的doc中URLClassLoader的两个构造器的描述:
URLClassLoader(URL[] urls)
         Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader.
URLClassLoader(URL[] urls, ClassLoader parent)
         Constructs a new URLClassLoader for the given URLs.
其中URL[] urls就是我们要设置的类搜索路径,parent就是这个classloader的parent classloader,默认的是system classloader。


好,现在我们能够动态的载入Class了,这样我们就可以利用newInstance方法来获得一个Object。但我们如何将此Object造型呢?可以将此Object造型成它本身的Class吗?

首先让我们来分析一下java源文件的编译,运行吧!javac命令是调用“JAVA_HOME/lib/tools.jar”中的“com.sun.tools.javac.Main”的compile方法来编译:

   public static int compile(String as[]);

   public static int compile(String as[], PrintWriter printwriter);

返回0表示编译成功,字符串数组as则是我们用javac命令编译时的参数,以空格划分。例如:
javac -classpath c:\foo\bar.jar;. -d c:\ c:\Some.java
则字符串数组as为{"-classpath","c:\\foo\\bar.jar;.","-d","c:\\","c:\\Some.java"},如果带有PrintWriter参数,则会把编译信息出到这个指定的printWriter中。默认的输出是System.err。

其中 Main是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,编译器在解析这个java源文件时所发现的它所依赖和引用的所有Class也将由system classloader载入,如果system classloader不能载入某个Class时,编译器将抛出一个“cannot resolve symbol”错误。

所以首先编译就通不过,也就是编译器无法编译一个引用了不在CLASSPATH中的未知Class的java源文件,而由于拼写错误或者没有把所需类库放到CLASSPATH中,大家一定经常看到这个“cannot resolve symbol”这个编译错误吧!

其次,就是我们把这个Class放到编译路径中,成功的进行了编译,然后在运行的时候不把它放入到CLASSPATH中而利用我们自己的 classloader来动态载入这个Class,这时候也会出现“java.lang.NoClassDefFoundError”的违例,为什么呢?

我们再来分析一下,首先调用这个造型语句的可执行的Class一定是由JVM使用Launcher初始化的system classloader载入的,根据全盘负责原则,当我们进行造型的时候,JVM也会使用system classloader来尝试载入这个Class来对实例进行造型,自然在system classloader寻找不到这个Class时就会抛出“java.lang.NoClassDefFoundError”的违例。

OK,现在让我们来总结一下,java文件的编译和Class的载入执行,都是使用Launcher初始化的system classloader作为类载入器的,我们无法动态的改变system classloader,更无法让JVM使用我们自己的classloader来替换system classloader,根据全盘负责原则,就限制了编译和运行时,我们无法直接显式的使用一个system classloader寻找不到的Class,即我们只能使用Java核心类库,扩展类库和CLASSPATH中的类库中的Class。

还不死心!再尝试一下这种情况,我们把这个Class也放入到CLASSPATH中,让system classloader能够识别和载入。然后我们通过自己的classloader来从指定的class文件中载入这个Class(不能够委托 parent载入,因为这样会被system classloader从CLASSPATH中将其载入),然后实例化一个Object,并造型成这个Class,这样JVM也识别这个Class(因为 system classloader能够定位和载入这个Class从CLASSPATH中),载入的也不是CLASSPATH中的这个Class,而是从 CLASSPATH外动态载入的,这样总行了吧!十分不幸的是,这时会出现“java.lang.ClassCastException”违例。

为什么呢?我们也来分析一下,不错,我们虽然从CLASSPATH外使用我们自己的classloader动态载入了这个Class,但将它的实例造型的时候是JVM会使用system classloader来再次载入这个Class,并尝试将使用我们的自己的classloader载入的Class的一个实例造型为system classloader载入的这个Class(另外的一个)。大家发现什么问题了吗?也就是我们尝试将从一个classloader载入的Class的一个实例造型为另外一个classloader载入的Class,虽然这两个Class的名字一样,甚至是从同一个class文件中载入。但不幸的是JVM 却认为这个两个Class是不同的,即JVM认为不同的classloader载入的相同的名字的Class(即使是从同一个class文件中载入的)是不同的!这样做的原因我想大概也是主要出于安全性考虑,这样就保证所有的核心Java类都是system classloader载入的,我们无法用自己的classloader载入的相同名字的Class的实例来替换它们的实例。

看到这里,聪明的读者一定想到了该如何动态载入我们的Class,实例化,造型并调用了吧!

那就是利用面向对象的基本特性之一的多形性。我们把我们动态载入的Class的实例造型成它的一个system classloader所能识别的父类就行了!这是为什么呢?我们还是要再来分析一次。当我们用我们自己的classloader来动态载入这我们只要把这个Class的时候,发现它有一个父类Class,在载入它之前JVM先会载入这个父类Class,这个父类Class是system classloader所能识别的,根据委托机制,它将由system classloader载入,然后我们的classloader再载入这个Class,创建一个实例,造型为这个父类Class,注意了,造型成这个父类 Class的时候(也就是上溯)是面向对象的java语言所允许的并且JVM也支持的,JVM就使用system classloader再次载入这个父类Class,然后将此实例造型为这个父类Class。大家可以从这个过程发现这个父类Class都是由 system classloader载入的,也就是同一个class loader载入的同一个Class,所以造型的时候不会出现任何异常。而根据多形性,调用这个父类的方法时,真正执行的是这个Class(非父类 Class)的覆盖了父类方法的方法。这些方法中也可以引用system classloader不能识别的Class,因为根据全盘负责原则,只要载入这个Class的classloader即我们自己定义的 classloader能够定位和载入这些Class就行了。

这样我们就可以事先定义好一组接口或者基类并放入CLASSPATH中,然后在执行的时候动态的载入实现或者继承了这些接口或基类的子类。还不明白吗?让我们来想一想Servlet吧,web application server能够载入任何继承了Servlet的Class并正确的执行它们,不管它实际的Class是什么,就是都把它们实例化成为一个Servlet Class,然后执行Servlet的init,doPost,doGet和destroy等方法的,而不管这个Servlet是从web- inf/lib和web-inf/classes下由system classloader的子classloader(即定制的classloader)动态载入。说了这么多希望大家都明白了。在applet,ejb等容器中,都是采用了这种机制.

对于以上各种情况,希望大家实际编写一些example来实验一下。

最后我再说点别的, classloader虽然称为类加载器,但并不意味着只能用来加载Class,我们还可以利用它也获得图片,音频文件等资源的URL,当然,这些资源必须在CLASSPATH中的jar类库中或目录下。我们来看API的doc中关于ClassLoader的两个寻找资源和Class的方法描述吧:
        public URL getResource(String name)
        用指定的名字来查找资源,一个资源是一些能够被class代码访问的在某种程度上依赖于代码位置的数据(图片,音频,文本等等)。
               一个资源的名字是以'/'号分隔确定资源的路径名的。
               这个方法将先请求parent classloader搜索资源,如果没有parent,则会在内置在虚拟机中的classloader(即bootstrap classloader)的路径中搜索。如果失败,这个方法将调用findResource(String)来寻找资源。
        public static URL getSystemResource(String name)
               从用来载入类的搜索路径中查找一个指定名字的资源。这个方法使用system class loader来定位资源。即相当于ClassLoader.getSystemClassLoader().getResource(name)。

例如:
   System.out.println(ClassLoader.getSystemResource("java/lang/String.class"));
的结果为:
   jar:文件:/C:/j2sdk1.4.1_01/jre/lib/rt.jar!/java/lang/String.class
表明String.class文件在rt.jar的java/lang目录中。
因此我们可以将图片等资源随同Class一同打包到jar类库中(当然,也可单独打包这些资源)并添加它们到class loader的搜索路径中,我们就可以无需关心这些资源的具体位置,让class loader来帮我们寻找了!
posted @ 2006-08-20 17:28 Long Long Ago 阅读(12559) | 评论 (5)编辑 收藏

最近做的gef编辑器在删除时遇到了一些问题,就是不能通过delete键删除,到处搜集资料,解决了,
首先需要在相应rcp工程中的ActionBarAdviser类中注册相应的Action,比如对应于deleteAction,我在方法org.eclipse.ui.application.ActionBarAdvisor#makeAction(IWorkbenchWindow)中注册deleteAction,如下:
protected void makeAction(final IWorkbenchWindow window){
    IAction delAction 
= ActionFactory.DELETE.create(window);
    register(delAction);
}


只是这么设置还是不能删除相应的图形元素,需要在相应的编辑器中重载init方法,添加如下的代码
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
    
// TODO Auto-generated method stub
    super.init(site, input);
    ActionRegistry registry 
= getActionRegistry();
    IActionBars bar 
= site.getActionBars();
    String id 
= ActionFactory.DELETE.getId();
    bar.setGlobalActionHandler(id,registry.getAction(id));
    bar.updateActionBars();
}

在这里仔细研究会发现,在第一段代码中实际上时创建了一个action,这是一个RetargetAction,而在super.init()方法会调用一个createAction方法,这里创建的是gef默认的redoAction undoAction selectionAction deleteAction saveAction.需要注意的是RetargetAction是一种可以跟踪当前活动的部分,由于retargetAction含有一个id,如果这个活动部分提供的handler的id和retargetAction的id相同,那么相应的对retargetAction的调用就转嫁成对当前这个活动部分的handle的调用,(当然如果根本就没有handle,那么这个action会disable).所以,我们可以看出来,这个retargetAction会在gef编辑器激活后调用gef的deleteAction.
posted @ 2006-08-19 17:35 Long Long Ago 阅读(1170) | 评论 (0)编辑 收藏

http://www.approc.com/

[Java|Eclipse|GEF]Figure是如何定位和设置大小?

有两种会创建图元:
1、打开图形文件时,先会创建所有的model,这样图元的定位和设置大小是依据图元model的size和location属性,通过图元EditPart.refreshVisuals()来设置的
2、通过拖放托盘里面的图标来建立的图元,会先设置model的size,然后通过model对应的figure.setPreferredSize()来设置了,而location则是通过鼠标的位置来确定的
posted @ 2006-08-14 11:18 Long Long Ago 阅读(659) | 评论 (0)编辑 收藏

http://www.approc.com/
现在在3.1里面访问资源文件变得比较简单了,用户可以通过继承osgi.util.NLS,典型例子:
public class MsgBoundle extends NLS{
      
private final static String BOUNDLE_NAME 
                       
= "resource.msg";
      
public static String mo_1;
      
public static String mo_2;

      
static{
         NLS.initializeMessage(BOUNDLE_NAME,
                       MsgBoundle.
class);
      }

}


好啦,现在就可以建立资源文件了,文件应该建在哪里呢?跟踪代码发现,这个由BOUNDLE_NAME决定,在MessageResourceBoundle.buildVariants()中,会将BOUNDLE_NAME中的“."替换成"/",然后再根据地区设定组合几种不同的资源文件名称,比如我的就是:

1、resource/msg_zh_CN.properties
2、resource/msg_zh.properties
3、resource/msg.properties
注意:这三个文件是有顺序的哦

然后通过EclipseClassLoader.getResource()来查找这些文件,并将文件中的值赋予给MsgBoundle对应的成员变量。
posted @ 2006-08-14 11:16 Long Long Ago 阅读(820) | 评论 (0)编辑 收藏

在linux(ubuntu)下引入了在windows工作时建立的一个pluginProject,但是发现,在plugin.xml中require包都没有了,在3.0以后这些require都是放在MANIFEST.MF文件中的,这两个文件是同步的,即在编辑plugin.xml文件视图时会看到MANIFEST.MF文件中的require,不过在从windows引入后就看不到了,不过这是发现MANIFEST.MF和他所在的目录META-INF都变成了小写,改成大写后,再update classpath就可以了。
posted @ 2006-07-19 10:26 Long Long Ago 阅读(328) | 评论 (0)编辑 收藏

仅列出标题
共4页: 上一页 1 2 3 4 下一页